aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/libhicnctrl/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'ctrl/libhicnctrl/src/test')
-rw-r--r--ctrl/libhicnctrl/src/test/CMakeLists.txt51
-rw-r--r--ctrl/libhicnctrl/src/test/common.cc13
-rw-r--r--ctrl/libhicnctrl/src/test/common.h51
-rw-r--r--ctrl/libhicnctrl/src/test/main.cc21
-rw-r--r--ctrl/libhicnctrl/src/test/test_data.cc97
-rw-r--r--ctrl/libhicnctrl/src/test/test_hicnlight_connection.cc132
-rw-r--r--ctrl/libhicnctrl/src/test/test_hicnlight_listener.cc138
-rw-r--r--ctrl/libhicnctrl/src/test/test_hicnlight_route.cc133
8 files changed, 636 insertions, 0 deletions
diff --git a/ctrl/libhicnctrl/src/test/CMakeLists.txt b/ctrl/libhicnctrl/src/test/CMakeLists.txt
new file mode 100644
index 000000000..7fdff476d
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/CMakeLists.txt
@@ -0,0 +1,51 @@
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##############################################################
+# Test sources
+##############################################################
+list(APPEND TESTS_SRC
+ main.cc
+ common.cc
+ test_data.cc
+ test_hicnlight_listener.cc
+ test_hicnlight_connection.cc
+ test_hicnlight_route.cc
+ ../modules/hicn_light/connection.c
+ ../modules/hicn_light/face.c
+ ../modules/hicn_light/listener.c
+ ../modules/hicn_light/route.c
+)
+
+##############################################################
+# Build single unit test executable and add it to test list
+##############################################################
+build_executable(libhicnctrl_tests
+ NO_INSTALL
+ SOURCES ${TESTS_SRC}
+ LINK_LIBRARIES
+ ${LIBRARIES}
+ ${LIBHICNCTRL_SHARED}
+ ${GTEST_LIBRARIES}
+ pthread
+ INCLUDE_DIRS
+ $<TARGET_PROPERTY:${LIBHICNCTRL_SHARED},INCLUDE_DIRECTORIES>
+ ${GTEST_INCLUDE_DIRS}
+ DEPENDS gtest ${LIBHICNCTRL_SHARED}
+ COMPONENT ${LIBHICNCTRL_COMPONENT}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+ LINK_FLAGS ${LINK_FLAGS}
+)
+
+add_test_internal(libhicnctrl_tests)
diff --git a/ctrl/libhicnctrl/src/test/common.cc b/ctrl/libhicnctrl/src/test/common.cc
new file mode 100644
index 000000000..075281d2e
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/common.cc
@@ -0,0 +1,13 @@
+#include "common.h"
+
+std::string dump_buffer(const char *name, uint8_t *buffer, size_t size) {
+ std::ostringstream oss;
+ oss << "const std::vector<uint8_t> " << name << " = {";
+ for (size_t i = 0; i < size; i++) {
+ if (i > 0) oss << ", ";
+ oss << "0x" << std::setw(2) << std::setfill('0') << std::hex
+ << static_cast<int>(buffer[i]);
+ }
+ oss << "};" << std::endl;
+ return oss.str();
+}
diff --git a/ctrl/libhicnctrl/src/test/common.h b/ctrl/libhicnctrl/src/test/common.h
new file mode 100644
index 000000000..8927c86ec
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/common.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HICNCTRL_TEST_COMMON
+#define HICNCTRL_TEST_COMMON
+
+#define BUFSIZE 8192
+
+#include <gtest/gtest.h>
+
+class TestHicnLight : public ::testing::Test {
+ protected:
+ TestHicnLight() {}
+ virtual ~TestHicnLight() {}
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+};
+
+class TestHicnLightSerialize : public TestHicnLight {
+ // TestHicnLightSerialize() {}
+ // virtual ~TestHicnLightSerialize() {}
+};
+
+class TestHicnLightParse : public TestHicnLight {
+ // TestHicnLightParse() {}
+ // virtual ~TestHicnLightParse() {}
+};
+
+std::string dump_buffer(const char *name, uint8_t *buffer, size_t size);
+
+#define EXPECT_PAYLOAD_EQ(BUFFER, SIZE, PAYLOAD) \
+ EXPECT_EQ(memcmp((BUFFER), &(PAYLOAD)[0], PAYLOAD.size()), 0) \
+ << dump_buffer(#PAYLOAD, (BUFFER), SIZE);
+
+#define EXPECT_PAYLOAD_EQ_STRUCT(BUFFER, SIZE, PAYLOAD) \
+ EXPECT_EQ(memcmp((BUFFER), (PAYLOAD), SIZE), 0) \
+ << dump_buffer("expected:", (uint8_t *)(BUFFER), SIZE);
+
+#endif /* HICNCTRL_TEST_COMMON */
diff --git a/ctrl/libhicnctrl/src/test/main.cc b/ctrl/libhicnctrl/src/test/main.cc
new file mode 100644
index 000000000..49cc28f66
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/main.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/ctrl/libhicnctrl/src/test/test_data.cc b/ctrl/libhicnctrl/src/test/test_data.cc
new file mode 100644
index 000000000..46debb0e7
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/test_data.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+extern "C" {
+#include <hicn/ctrl/objects.h>
+#include <hicn/ctrl/data.h>
+#include <hicn/ctrl/object.h>
+}
+
+#include "common.h"
+
+namespace {
+
+TEST_F(TestHicnLight, TestHicnLightData) {
+ hc_object_t object;
+ memset(&object, 0, sizeof(hc_object_t));
+
+ int rc;
+ hc_data_t* data = hc_data_create(OBJECT_TYPE_FACE);
+ hc_data_set_max_size(data, 2);
+
+ ASSERT_EQ(hc_data_get_size(data), 0) << "Initial data size should be zero";
+
+ /* Try to allocate more than max */
+ rc = hc_data_allocate(data, 5);
+ ASSERT_EQ(rc, -1) << "Allocating above max_size should fail";
+
+ /* Allocate room for two objects */
+ rc = hc_data_allocate(data, 2);
+ ASSERT_EQ(rc, 0) << "Allocating data the first time should succeed";
+
+ ASSERT_EQ(hc_data_get_size(data), 0)
+ << "Initial size should be 0 after allocation";
+
+ /* Try to allocate twice */
+ rc = hc_data_allocate(data, 2);
+ ASSERT_EQ(rc, -1) << "Allocating data multiple times should fail";
+
+ ASSERT_EQ(hc_data_get_size(data), 0)
+ << "Size after failed push should remain unchanged";
+
+ /* Push a first object */
+ rc = hc_data_push(data, &object);
+ ASSERT_EQ(rc, 0) << "First push should succeed";
+
+ ASSERT_EQ(hc_data_get_size(data), 1)
+ << "Data size first successful push should be 1";
+
+ /* Push a second object */
+ rc = hc_data_push(data, &object);
+ ASSERT_EQ(rc, 0) << "Second push should succeed";
+
+ ASSERT_EQ(hc_data_get_size(data), 2)
+ << "Data size after second successful push should be 2";
+
+ /* Push a third object, exceeding the allocated size */
+ rc = hc_data_push(data, &object);
+ ASSERT_EQ(rc, -1) << "Third push on full data of size 2 should fail";
+
+ /* Clear */
+ rc = hc_data_clear(data);
+ ASSERT_EQ(rc, 0) << "Clear should always succeed";
+
+ rc = hc_data_push(data, &object);
+ ASSERT_EQ(rc, 0) << "Pushing element after reallocation should succeed";
+
+ ASSERT_EQ(hc_data_get_size(data), 1) << "Size after first push should be one";
+ // XXX
+
+ /* Try to push an invalid object */
+ // XXX so far NULL
+ rc = hc_data_push(data, NULL);
+ ASSERT_EQ(rc, -1) << "Pushing invalid element should fail";
+
+ ASSERT_EQ(hc_data_get_size(data), 1)
+ << "Size after push failure should remain unchanged";
+ // XXX
+
+ hc_data_free(data);
+}
+
+} // namespace
diff --git a/ctrl/libhicnctrl/src/test/test_hicnlight_connection.cc b/ctrl/libhicnctrl/src/test/test_hicnlight_connection.cc
new file mode 100644
index 000000000..53dd88ac3
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/test_hicnlight_connection.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+#include <hicn/ctrl/object.h>
+
+#include "../modules/hicn_light/connection.h"
+#include "common.h"
+
+namespace {
+
+const hc_object_t valid_connection = {
+ .connection = {.id = 0,
+ .name = {'l', 's', 't', 0},
+ .interface_name = {'l', 'o', 0},
+ .netdevice_type = NETDEVICE_TYPE_WIRED,
+ .type = FACE_TYPE_UDP,
+ .family = AF_INET,
+ .local_addr = IPV4_LOOPBACK,
+ .local_port = 9695,
+ .remote_addr = IPV4_LOOPBACK,
+ .remote_port = 9695,
+ .admin_state = FACE_STATE_UP,
+ .priority = 0,
+ .tags = POLICY_TAGS_EMPTY,
+ .state = FACE_STATE_UP}};
+
+const std::vector<uint8_t> valid_connection_create_payload = {
+ /* header */
+ 0xc0, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* char name[SYMBOLIC_NAME_LEN] = "lst"; */
+ 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* ip_address_t local_addr = [padding] 127.0.0.1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* ip_address_t remote_addr = [padding] 127.0.0.1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* uint16_t local_port = 9695; */
+ 0x25, 0xdf,
+ /* uint16_t remote_port = 9695; */
+ 0x25, 0xdf,
+ /* int family = AF_INET; */
+ 0x02,
+ /* face_type_t type = FACE_TYPE_UDP_LISTENER; */
+ 0x05,
+ /* uint8_t admin_state = FACE_STATE_UP; */
+ 0x02,
+ /* Padding ? */
+ 0x00,
+ /* uint32_t priority = 0; */
+ 0x00, 0x00, 0x00, 0x00,
+ /* policy_tags_t tags; */
+ 0x00, 0x00, 0x00, 0x00};
+
+const std::vector<uint8_t> valid_connection_delete_payload = {
+ 0xc0, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x73, 0x74, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+const std::vector<uint8_t> valid_connection_list_payload = {
+ 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeConnectionCreate) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.connection, &valid_connection, sizeof(hc_connection_t));
+
+ hc_serialize_t fn = hicnlight_connection_module_ops.serialize[ACTION_CREATE];
+ size_t n = fn(&obj, buf);
+
+ // XXX debug
+ // THIS HAS UNINIT VALUES
+ std::cout << "n=" << n << std::endl;
+ EXPECT_EQ(memcmp(buf, buf, 60), 0);
+ EXPECT_EQ(memcmp(buf, buf, 62), 0);
+ EXPECT_EQ(memcmp(buf, buf, 64), 0); // XXX we start having issues
+ EXPECT_EQ(memcmp(buf, buf, 66), 0);
+ EXPECT_EQ(memcmp(buf, buf, 68), 0);
+ EXPECT_EQ(memcmp(buf, buf, 70), 0);
+ EXPECT_EQ(memcmp(buf, buf, 72), 0);
+ // XXX debug
+
+ EXPECT_EQ(n, valid_connection_create_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_connection_create_payload);
+}
+
+// TODO
+// - create with id != 0
+// - create with invalid fields, non zero-terminated strings, etc.
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeConnectionDelete) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.connection, &valid_connection, sizeof(hc_connection_t));
+
+ hc_serialize_t fn = hicnlight_connection_module_ops.serialize[ACTION_DELETE];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_connection_delete_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_connection_delete_payload);
+}
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeConnectionList) {
+ uint8_t buf[BUFSIZE];
+
+ hc_serialize_t fn = hicnlight_connection_module_ops.serialize[ACTION_LIST];
+ size_t n = fn(NULL, buf);
+
+ EXPECT_EQ(n, valid_connection_list_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_connection_list_payload);
+}
+
+} // namespace
diff --git a/ctrl/libhicnctrl/src/test/test_hicnlight_listener.cc b/ctrl/libhicnctrl/src/test/test_hicnlight_listener.cc
new file mode 100644
index 000000000..fb3df39a8
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/test_hicnlight_listener.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+extern "C" {
+#include <hicn/ctrl/object.h>
+#include <hicn/ctrl/objects/listener.h>
+#include "../modules/hicn_light/listener.h"
+}
+
+#include "common.h"
+
+namespace {
+
+static const hc_object_t valid_listener = {
+ .listener = {.name = {'l', 's', 't', 0},
+ .interface_name = {'l', 'o', 0},
+ .id = 0,
+ .type = FACE_TYPE_UDP_LISTENER,
+ .family = AF_INET,
+ .local_addr = IPV4_LOOPBACK,
+ .local_port = 9695}};
+
+const std::vector<uint8_t> valid_listener_create_payload = {
+ /* header */
+ 0xc0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* char name[SYMBOLIC_NAME_LEN] = "lst"; */
+ 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* char interface_name[INTERFACE_LEN] = "lo"; */
+ 0x6c, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* ip_address_t local_addr = [padding] 127.0.0.1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* uint16_t local_port = 9695; */
+ 0x25, 0xdf,
+ /* int family = AF_INET; */
+ 0x02,
+ /* face_type_t type = FACE_TYPE_UDP_LISTENER; */
+ 0x06};
+
+const std::vector<uint8_t> valid_listener_delete_payload = {
+ /* header */
+ 0xc0, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* char symbolicOrListenerid[SYMBOLIC_NAME_LEN] = "lst"; */
+ 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+const std::vector<uint8_t> valid_listener_list_payload = {
+ /* header */
+ 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/* @see <hicn/ctrl/objects/listener.h> */
+const std::vector<uint8_t> valid_listener_payload = {
+ /* char name[SYMBOLIC_NAME_LEN] = "lst"; */
+ 0x6c, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* char interface_name[INTERFACE_LEN] = "lo"; */
+ 0x6c, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* ip_address_t local_addr = [padding] 127.0.0.1 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* uint32_t id = 0; */
+ 0x00, 0x00, 0x00, 0x00,
+ /* uint16_t local_port = 9695; */
+ 0x25, 0xdf,
+ /* face_type_t type = FACE_TYPE_UDP */
+ 0x06,
+ /* int family = AF_INET; */
+ 0x02};
+
+TEST_F(TestHicnLightParse, TestHicnLightParseListener) {
+ /* Parse payload into an object */
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ int rc = hicnlight_listener_module_ops.parse(
+ &valid_listener_payload[0], valid_listener_payload.size(), &obj);
+ EXPECT_EQ(rc, 0);
+ EXPECT_EQ(hc_listener_cmp(&obj.listener, &valid_listener.listener), 0);
+}
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeListenerCreate) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.listener, &valid_listener, sizeof(hc_listener_t));
+
+ hc_serialize_t fn = hicnlight_listener_module_ops.serialize[ACTION_CREATE];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_listener_create_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_listener_create_payload);
+}
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeListenerDelete) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.listener, &valid_listener, sizeof(hc_listener_t));
+
+ hc_serialize_t fn = hicnlight_listener_module_ops.serialize[ACTION_DELETE];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_listener_delete_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_listener_delete_payload);
+}
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeListenerList) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.listener, &valid_listener, sizeof(hc_listener_t));
+
+ hc_serialize_t fn = hicnlight_listener_module_ops.serialize[ACTION_LIST];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_listener_list_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_listener_list_payload);
+}
+} // namespace
diff --git a/ctrl/libhicnctrl/src/test/test_hicnlight_route.cc b/ctrl/libhicnctrl/src/test/test_hicnlight_route.cc
new file mode 100644
index 000000000..d48066ba2
--- /dev/null
+++ b/ctrl/libhicnctrl/src/test/test_hicnlight_route.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <sstream>
+
+extern "C" {
+#include <hicn/ctrl/object.h>
+#include "../modules/hicn_light/route.h"
+}
+
+#include "common.h"
+
+namespace {
+
+const hc_object_t valid_route = {
+ .route = {.face_id = 1,
+ .face_name = {0}, // NULL, use face_id instead
+ .family = AF_INET,
+ .remote_addr = IPV4_LOOPBACK,
+ .len = 16,
+ .cost = 1,
+ .face = {0}}};
+
+const std::vector<uint8_t> valid_route_create_payload = {
+ /* uint8_t message_type = REQUEST_LIGHT */
+ 0xc0,
+ /* uint8_t command_id = COMMAND_TYPE_ROUTE_ADD */
+ 0x08,
+ /* uint16_t length = 1 */
+ 0x01, 0x00,
+ /* uint32_t seq_num = 0 */
+ 0x00, 0x00, 0x00, 0x00,
+ /* char symbolic_or_connid[16] = "1\0" */
+ 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* hicn_ip_address_t address = {0, 0, 0, 127.0.0.1} */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* */
+ 0x01,
+ /* */
+ 0x00,
+ /* */
+ 0x02,
+ /* */
+ 0x10};
+
+const std::vector<uint8_t> valid_route_delete_payload = {
+ /* uint8_t message_type = REQUEST_LIGHT */
+ 0xc0,
+ /* uint8_t command_id = COMMAND_TYPE_ROUTE_REMOVE */
+ 0x09,
+ /* uint16_t length = 1 */
+ 0x01, 0x00,
+ /* uint32_t seq_num = 0 */
+ 0x00, 0x00, 0x00, 0x00,
+
+ /* char symbolic_or_connid[16] = "1\0" */
+ 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* hicn_ip_address_t address = {0, 0, 0, 127.0.0.1} */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x00, 0x00, 0x01,
+ /* uint8_t family = AF_INET (2) */
+ 0x02,
+ /* uint8_t len = 16 */
+ 0x10,
+ /* 2-byte padding */
+ 0x00, 0x00};
+
+const std::vector<uint8_t> valid_route_list_payload = {0xc0, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeRouteCreate) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.route, &valid_route, sizeof(hc_route_t));
+
+ hc_serialize_t fn = hicnlight_route_module_ops.serialize[ACTION_CREATE];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_route_create_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_route_create_payload);
+}
+
+// TODO
+// - create with id != 0
+// - create with invalid fields, non zero-terminated strings, etc.
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeRouteDelete) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.route, &valid_route, sizeof(hc_route_t));
+
+ hc_serialize_t fn = hicnlight_route_module_ops.serialize[ACTION_DELETE];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_route_delete_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_route_delete_payload);
+}
+
+TEST_F(TestHicnLightSerialize, TestHicnLightSerializeRouteList) {
+ uint8_t buf[BUFSIZE];
+
+ hc_object_t obj;
+ memset(&obj, 0, sizeof(hc_object_t));
+ memcpy(&obj.route, &valid_route, sizeof(hc_route_t));
+
+ hc_serialize_t fn = hicnlight_route_module_ops.serialize[ACTION_LIST];
+ size_t n = fn(&obj, buf);
+
+ EXPECT_EQ(n, valid_route_list_payload.size());
+ EXPECT_PAYLOAD_EQ(buf, n, valid_route_list_payload);
+}
+
+} // namespace