lldp: add test case
authorBeniamino Galvani <bgalvani@redhat.com>
Tue, 10 Nov 2015 13:17:50 +0000 (14:17 +0100)
committerBeniamino Galvani <bgalvani@redhat.com>
Tue, 10 Nov 2015 13:25:05 +0000 (14:25 +0100)
Add a test for the LLDP listener to ensure that things don't
accidentally break when we import new code from systemd upstream.

https://bugzilla.gnome.org/show_bug.cgi?id=757005

configure.ac
src/Makefile.am
src/devices/Makefile.am [new file with mode: 0644]
src/devices/tests/Makefile.am [new file with mode: 0644]
src/devices/tests/test-lldp.c [new file with mode: 0644]

index c8e7913..7b4ca9a 100644 (file)
@@ -1031,6 +1031,8 @@ src/platform/Makefile
 src/platform/tests/Makefile
 src/rdisc/Makefile
 src/rdisc/tests/Makefile
+src/devices/Makefile
+src/devices/tests/Makefile
 src/devices/adsl/Makefile
 src/devices/bluetooth/Makefile
 src/devices/team/Makefile
index 096cd57..0c96c45 100644 (file)
@@ -26,6 +26,7 @@ SUBDIRS += \
        dhcp-manager/tests \
        dnsmasq-manager/tests \
        platform \
+       devices \
        rdisc \
        supplicant-manager/tests \
        tests
diff --git a/src/devices/Makefile.am b/src/devices/Makefile.am
new file mode 100644 (file)
index 0000000..3c6155b
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = tests
diff --git a/src/devices/tests/Makefile.am b/src/devices/tests/Makefile.am
new file mode 100644 (file)
index 0000000..4b1595e
--- /dev/null
@@ -0,0 +1,42 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/include \
+       -I$(top_builddir)/include \
+       -I$(top_srcdir)/libnm-core \
+       -I$(top_builddir)/libnm-core \
+       -I$(top_srcdir)/src/platform \
+       -I$(top_srcdir)/src/devices \
+       -I$(top_srcdir)/src/systemd/ \
+       -I$(top_srcdir)/src/systemd/src/systemd/ \
+       -I$(top_srcdir)/src/systemd/src/libsystemd-network/ \
+       -I$(top_srcdir)/src \
+       -I$(top_builddir)/src \
+       -DG_LOG_DOMAIN=\""NetworkManager"\" \
+       -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
+       -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \
+       $(GLIB_CFLAGS)
+
+AM_CFLAGS = $(CODE_COVERAGE_CFLAGS)
+AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS)
+DEVICES_LDADD = \
+       $(top_builddir)/src/libNetworkManager.la
+
+@GNOME_CODE_COVERAGE_RULES@
+
+noinst_PROGRAMS = \
+       test-lldp
+
+test_lldp_SOURCES = \
+       test-lldp.c \
+       ../nm-lldp-listener.c \
+       $(top_srcdir)/src/platform/tests/test-common.c
+
+test_lldp_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -I$(top_srcdir)/src/platform/tests \
+       -DSETUP=nm_linux_platform_setup
+
+test_lldp_LDADD = $(DEVICES_LDADD)
+
+@VALGRIND_RULES@
+TESTS = \
+       test-lldp
diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
new file mode 100644 (file)
index 0000000..c339d9c
--- /dev/null
@@ -0,0 +1,221 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * 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) 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "nm-default.h"
+#include "nm-lldp-listener.h"
+#include "test-common.h"
+
+typedef struct {
+       int ifindex;
+       int fd;
+       guint8 mac[ETH_ALEN];
+} test_fixture;
+
+#define TEST_IFNAME "nm-tap-test0"
+
+static void
+fixture_setup (test_fixture *fixture, gconstpointer user_data)
+{
+       const NMPlatformLink *link;
+       struct ifreq ifr = { };
+       int fd, s;
+
+       fd = open ("/dev/net/tun", O_RDWR);
+       g_assert (fd >= 0);
+
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+       strncpy (ifr.ifr_name, TEST_IFNAME, IFNAMSIZ);
+       g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0);
+
+       /* Bring the interface up */
+       s = socket (AF_INET, SOCK_DGRAM, 0);
+       g_assert (s >= 0);
+       ifr.ifr_flags |= IFF_UP;
+       g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0);
+       close (s);
+
+       nm_platform_process_events (NM_PLATFORM_GET);
+       link = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, TEST_IFNAME);
+       g_assert (link);
+       fixture->ifindex = link->ifindex;
+       fixture->fd = fd;
+       memcpy (fixture->mac, link->addr.data, ETH_ALEN);
+}
+
+typedef struct {
+       int num_called;
+} TestInfo;
+
+static gboolean
+loop_quit (gpointer user_data)
+{
+       g_main_loop_quit ((GMainLoop *) user_data);
+       return G_SOURCE_REMOVE;
+}
+
+static void
+lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec,
+                        gpointer user_data)
+{
+       TestInfo *info = user_data;
+
+       info->num_called++;
+}
+
+static GVariant *
+get_lldp_neighbor_attribute (GVariant *neighbors,
+                             const char *chassis, const char *port,
+                             const char *name)
+{
+       GVariantIter iter, attrs_iter;
+       GVariant *variant, *attr_variant;
+       const char *attr_name;
+       GVariant *chassis_v, *port_v, *attr_v;
+
+       g_return_val_if_fail (g_variant_is_of_type (neighbors,
+                                                   G_VARIANT_TYPE ("aa{sv}")),
+                             NULL);
+       g_variant_iter_init (&iter, neighbors);
+
+       while (g_variant_iter_next (&iter, "@a{sv}", &variant)) {
+               g_variant_iter_init (&attrs_iter, variant);
+               chassis_v = NULL;
+               port_v = NULL;
+               attr_v = NULL;
+
+               while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_variant)) {
+                       if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_CHASSIS_ID))
+                               chassis_v = attr_variant;
+                       else if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_PORT_ID))
+                               port_v = attr_variant;
+                       else if (!g_strcmp0 (attr_name, name))
+                               attr_v = attr_variant;
+               }
+
+               if (   g_variant_is_of_type (chassis_v, G_VARIANT_TYPE_STRING)
+                   && g_variant_is_of_type (port_v, G_VARIANT_TYPE_STRING)
+                   && !g_strcmp0 (chassis, g_variant_get_string (chassis_v, NULL))
+                   && !g_strcmp0 (port, g_variant_get_string (port_v, NULL))) {
+
+                       g_variant_ref (attr_v);
+                       g_variant_unref (variant);
+
+                       return attr_v;
+               }
+               g_variant_unref (variant);
+       }
+
+       /* neighbor not found */
+       return NULL;
+}
+
+static void
+test_receive_frame (test_fixture *fixture, gconstpointer user_data)
+{
+       NMLldpListener *listener;
+       GMainLoop *loop;
+       TestInfo info = { };
+       GVariant *neighbors, *attr;
+       uint8_t frame[] = {
+               /* Ethernet header */
+               0x01, 0x80, 0xc2, 0x00, 0x00, 0x03,     /* Destination MAC */
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06,     /* Source MAC */
+               0x88, 0xcc,                             /* Ethertype */
+               /* LLDP mandatory TLVs */
+               0x02, 0x07, 0x04, 0x00, 0x01, 0x02,     /* Chassis: MAC, 00:01:02:03:04:05 */
+               0x03, 0x04, 0x05,
+               0x04, 0x04, 0x05, 0x31, 0x2f, 0x33,     /* Port: interface name, "1/3" */
+               0x06, 0x02, 0x00, 0x78,                 /* TTL: 120 seconds */
+               /* LLDP optional TLVs */
+               0x08, 0x04, 0x50, 0x6f, 0x72, 0x74,     /* Port Description: "Port" */
+               0x0a, 0x03, 0x53, 0x59, 0x53,           /* System Name: "SYS" */
+               0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00,     /* System Description: "foo" (NULL-terminated) */
+               0x00, 0x00                              /* End Of LLDPDU */
+       };
+
+       listener = nm_lldp_listener_new ();
+       g_assert (listener != NULL);
+       g_assert (nm_lldp_listener_start (listener, fixture->ifindex, TEST_IFNAME, fixture->mac, ETH_ALEN, NULL));
+
+       g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS,
+                         (GCallback) lldp_neighbors_changed, &info);
+       loop = g_main_loop_new (NULL, FALSE);
+       g_timeout_add_seconds (1, loop_quit, loop);
+
+       g_assert (write (fixture->fd, frame, sizeof (frame)) == sizeof (frame));
+       g_assert (write (fixture->fd, frame, sizeof (frame)) == sizeof (frame));
+
+       g_main_loop_run (loop);
+
+       g_assert_cmpint (info.num_called, ==, 1);
+       neighbors = nm_lldp_listener_get_neighbors (listener);
+       g_assert (neighbors != NULL);
+
+       /* Check port description */
+       attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+                                           NM_LLDP_ATTR_PORT_DESCRIPTION);
+       g_assert (attr != NULL);
+       g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+       g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "Port");
+
+       /* Check system name */
+       attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+                                           NM_LLDP_ATTR_SYSTEM_NAME);
+       g_assert (attr != NULL);
+       g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+       g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "SYS");
+
+       /* Check destination */
+       attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3",
+                                           NM_LLDP_ATTR_DESTINATION);
+       g_assert (attr != NULL);
+       g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING));
+       g_assert_cmpstr (g_variant_get_string (attr, NULL), ==,
+                        NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE);
+
+       g_clear_pointer (&loop, g_main_loop_unref);
+}
+
+static void
+fixture_teardown (test_fixture *fixture, gconstpointer user_data)
+{
+       nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex);
+}
+
+void
+init_tests (int *argc, char ***argv)
+{
+       nmtst_init_assert_logging (argc, argv, "WARN", "ALL");
+}
+
+void
+setup_tests (void)
+{
+       g_test_add ("/lldp/receive_frame", test_fixture, NULL, fixture_setup,
+                   test_receive_frame, fixture_teardown);
+}