diff options
Diffstat (limited to 'hicn-light/src/hicn/test')
24 files changed, 4160 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/test/CMakeLists.txt b/hicn-light/src/hicn/test/CMakeLists.txt new file mode 100644 index 000000000..0ded4253d --- /dev/null +++ b/hicn-light/src/hicn/test/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) 2021 Cisco and/or its affiliates. + +include(BuildMacros) + +list(APPEND TESTS_SRC + test-bitmap.cc + test-configuration.cc + test-hash.cc + test-khash.cc + test-loop.cc + test-pool.cc + test-parser.cc + test-ctrl.cc + test-ring.cc + test-vector.cc + test-msgbuf_pool.cc + test-nexthops.cc + test-connection_table.cc + test-listener_table.cc + test-packet_cache.cc + test-strategy-load-balancing.cc + test-strategy-random.cc + test-strategy-replication.cc + test-strategy-best-path.cc + test-subscription.cc + test-local_prefixes.cc + test-probe_generator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/../config/command_listener.c + ${CMAKE_CURRENT_SOURCE_DIR}/../config/command_route.c + main.cc +) + +build_executable(hicn_light_tests + NO_INSTALL + SOURCES ${TESTS_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_STATIC} ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} + DEPENDS gtest ${LIBHICNCTRL_STATIC} ${LIBHICN_LIGHT_SHARED} + COMPONENT ${HICN_LIGHT} + DEFINITIONS "${COMPILER_DEFINITIONS}" +) + +add_test_internal(hicn_light_tests) diff --git a/hicn-light/src/hicn/test/main.cc b/hicn-light/src/hicn/test/main.cc new file mode 100644 index 000000000..49cc28f66 --- /dev/null +++ b/hicn-light/src/hicn/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/hicn-light/src/hicn/test/test-bitmap.cc b/hicn-light/src/hicn/test/test-bitmap.cc new file mode 100644 index 000000000..f1bf1ae5a --- /dev/null +++ b/hicn-light/src/hicn/test/test-bitmap.cc @@ -0,0 +1,133 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/bitmap.h> +} + +#define DEFAULT_SIZE 10 + +class BitmapTest : public ::testing::Test { + protected: + BitmapTest() {} + + virtual ~BitmapTest() {} + + bitmap_t* bitmap; +}; + +/* + * TEST: bitmap allocation + */ +TEST_F(BitmapTest, BitmapAllocation) { + int rc; + + /* + * We take a value < 32 on purpose to avoid confusion on the choice of a 32 + * or 64 bit integer for storage + */ + size_t size_not_pow2 = DEFAULT_SIZE; + bitmap_init(bitmap, size_not_pow2, 0); + + /* + * Bitmap should have been allocated with a size rounded to the next power + * of 2 + */ + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* By default, no element should be set */ + EXPECT_FALSE(bitmap_is_set(bitmap, 0)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 0)); + + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + EXPECT_FALSE(bitmap_is_set(bitmap, size_not_pow2 - 1)); + EXPECT_TRUE(bitmap_is_unset(bitmap, size_not_pow2 - 1)); + + /* Bitmap should not have been reallocated */ + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* After setting a bit after the end, bitmap should have been reallocated */ + bitmap_set(bitmap, sizeof(bitmap[0]) * 8 - 1); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + /* After setting a bit after the end, bitmap should have been reallocated */ + rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8); + EXPECT_GE(rc, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); + + rc = bitmap_set(bitmap, sizeof(bitmap[0]) * 8 + 1); + EXPECT_GE(rc, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 2UL); + + bitmap_free(bitmap); + + size_t size_pow2 = 16; + + /* Limiting test for allocation size */ + bitmap_init(bitmap, size_pow2, 0); + EXPECT_EQ(bitmap_get_alloc_size(bitmap), 1UL); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapSet) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set(bitmap, 20); + EXPECT_TRUE(bitmap_is_set(bitmap, 20)); + EXPECT_FALSE(bitmap_is_unset(bitmap, 20)); + EXPECT_FALSE(bitmap_is_set(bitmap, 19)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 19)); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapUnSet) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set(bitmap, 20); + bitmap_set(bitmap, 19); + bitmap_unset(bitmap, 20); + EXPECT_FALSE(bitmap_is_set(bitmap, 20)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 20)); + EXPECT_TRUE(bitmap_is_set(bitmap, 19)); + EXPECT_FALSE(bitmap_is_unset(bitmap, 19)); + + bitmap_free(bitmap); +} + +TEST_F(BitmapTest, BitmapSetTo) { + bitmap_init(bitmap, DEFAULT_SIZE, 0); + + bitmap_set_to(bitmap, 40); + EXPECT_TRUE(bitmap_is_set(bitmap, 20)); + EXPECT_TRUE(bitmap_is_set(bitmap, 21)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 41)); + EXPECT_TRUE(bitmap_is_unset(bitmap, 42)); + + bitmap_free(bitmap); +} diff --git a/hicn-light/src/hicn/test/test-configuration.cc b/hicn-light/src/hicn/test/test-configuration.cc new file mode 100644 index 000000000..b631bb20b --- /dev/null +++ b/hicn-light/src/hicn/test/test-configuration.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/config/configuration.h> +} + +static inline size_t CS_SIZE = 10; +static inline char CONFIG_FILE[] = "setup.conf"; +static inline int LOG_LEVEL = LOG_DEBUG; +static inline char LOG_FILE[] = "/dev/null"; +static inline uint16_t PORT = 1234; +static inline uint16_t CONF_PORT = 5678; +static inline bool IS_DAEMON_MODE = true; +static inline char PREFIX[] = "b001::/16"; +static inline char PREFIX_2[] = "c001::/16"; +static inline strategy_type_t STRATEGY_TYPE = STRATEGY_TYPE_BESTPATH; + +class ConfigurationTest : public ::testing::Test { + protected: + ConfigurationTest() { + config = configuration_create(); + log_conf.log_level = LOG_FATAL; + log_conf.log_file = NULL; + } + virtual ~ConfigurationTest() { configuration_free(config); } + + configuration_t *config; +}; + +TEST_F(ConfigurationTest, CreateConfiguration) { + // Check configuration creation + ASSERT_NE(config, nullptr); +} + +TEST_F(ConfigurationTest, SetGeneralParameters) { + configuration_set_cs_size(config, CS_SIZE); + size_t cs_size = configuration_get_cs_size(config); + EXPECT_EQ(cs_size, CS_SIZE); + + configuration_set_fn_config(config, CONFIG_FILE); + const char *config_file = configuration_get_fn_config(config); + EXPECT_EQ(config_file, CONFIG_FILE); + + configuration_set_port(config, PORT); + uint16_t port = configuration_get_port(config); + EXPECT_EQ(port, PORT); + + configuration_set_configuration_port(config, CONF_PORT); + uint16_t conf_port = configuration_get_configuration_port(config); + EXPECT_EQ(conf_port, CONF_PORT); + + configuration_set_daemon(config, IS_DAEMON_MODE); + bool is_daemon_mode = configuration_get_daemon(config); + EXPECT_EQ(is_daemon_mode, IS_DAEMON_MODE); +} + +TEST_F(ConfigurationTest, SetLogParameters) { + configuration_set_loglevel(config, LOG_LEVEL); + int log_level = configuration_get_loglevel(config); + EXPECT_EQ(log_level, LOG_LEVEL); + EXPECT_EQ(log_conf.log_level, LOG_LEVEL); + + configuration_set_logfile(config, LOG_FILE); + const char *log_file = configuration_get_logfile(config); + EXPECT_EQ(log_file, LOG_FILE); + int write_fd = configuration_get_logfile_fd(config); + EXPECT_NE(write_fd, -1); +} + +TEST_F(ConfigurationTest, SetStrategyParameter) { + configuration_set_strategy(config, PREFIX, STRATEGY_TYPE); + strategy_type_t strategy_type = configuration_get_strategy(config, PREFIX); + EXPECT_EQ(strategy_type, STRATEGY_TYPE); + + // Check strategy for non-registered prefix + strategy_type = configuration_get_strategy(config, PREFIX_2); + EXPECT_EQ(strategy_type, STRATEGY_TYPE_UNDEFINED); +} diff --git a/hicn-light/src/hicn/test/test-connection_table.cc b/hicn-light/src/hicn/test/test-connection_table.cc new file mode 100644 index 000000000..6bbf478e2 --- /dev/null +++ b/hicn-light/src/hicn/test/test-connection_table.cc @@ -0,0 +1,250 @@ +/* + * 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 <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/connection_table.h> +} + +#define CONNECTION_NAME "connection_name_test" +#define CONNECTION_NAME_2 "connection_name_test_2" + +class ConnectionTableTest : public ::testing::Test { + protected: + ConnectionTableTest() { + log_conf.log_level = LOG_INFO; + + conn_table_ = connection_table_create(); + pair_ = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + } + virtual ~ConnectionTableTest() { connection_table_free(conn_table_); } + + connection_table_t *conn_table_; + connection_t *connection_; + address_pair_t pair_; +}; + +TEST_F(ConnectionTableTest, CreateTable) { + /* Check connection_table allocation */ + EXPECT_NE(conn_table_, nullptr); + + /* Check connection_table size */ + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)0); +} + +TEST_F(ConnectionTableTest, AddConnection) { + // Add connection to connection table + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)1); + EXPECT_NE(connection_, nullptr); + + // Get connection by name and by pair + khiter_t k_name = kh_get_ct_name(conn_table_->id_by_name, CONNECTION_NAME); + EXPECT_NE(k_name, kh_end(conn_table_->id_by_name)); + khiter_t k_pair = kh_get_ct_pair(conn_table_->id_by_pair, &pair_); + EXPECT_NE(k_pair, kh_end(conn_table_->id_by_pair)); +} + +TEST_F(ConnectionTableTest, GetConnection) { + // Add connection to connection table + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)1); + EXPECT_NE(connection_, nullptr); + + // Get connection by name + connection_t *connection_retrieved = + connection_table_get_by_name(conn_table_, CONNECTION_NAME); + ASSERT_NE(connection_retrieved, nullptr); + EXPECT_EQ(connection_retrieved, connection_); + + // Get connection by pair + connection_retrieved = connection_table_get_by_pair(conn_table_, &pair_); + ASSERT_NE(connection_retrieved, nullptr); + EXPECT_EQ(connection_retrieved, connection_); +} + +TEST_F(ConnectionTableTest, GetConnectionWithIdOutOfRange) { + connection_t *connection = _connection_table_get_by_id(conn_table_, ~0); + EXPECT_EQ(connection, nullptr); +} + +TEST_F(ConnectionTableTest, GetConnectionWithInvalidId) { + // First connection inserted has always id equal to 0 + int non_valid_id = 5; + + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + connection_t *connection_not_found = + connection_table_get_by_id(conn_table_, non_valid_id); + ASSERT_EQ(connection_not_found, nullptr); +} + +TEST_F(ConnectionTableTest, GetConnectionWithValidId) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_connection_id(conn_table_, connection_); + connection_t *connection_found = connection_table_get_by_id(conn_table_, id); + ASSERT_EQ(connection_found, connection_); +} + +TEST_F(ConnectionTableTest, GetConnectionIdFromValidName) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_id_by_name(conn_table_, CONNECTION_NAME); + ASSERT_TRUE(listener_id_is_valid(id)); +} + +TEST_F(ConnectionTableTest, GetConnectionIdFromInvalidName) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + int id = connection_table_get_id_by_name(conn_table_, CONNECTION_NAME_2); + ASSERT_FALSE(listener_id_is_valid(id)); +} + +TEST_F(ConnectionTableTest, RemoveConnection) { + // Add connection (connection name and pair must be set) + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + connection_->name = (char *)CONNECTION_NAME; + connection_->pair = pair_; + + // Remove connection + int id = connection_table_get_connection_id(conn_table_, connection_); + connection_table_remove_by_id(conn_table_, id); + + // Check connection table size + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)0); + + // Check that previous connection is not valid anymore + connection_t *connection_not_found = + connection_table_get_by_id(conn_table_, id); + EXPECT_EQ(connection_not_found, nullptr); + connection_not_found = + connection_table_get_by_name(conn_table_, CONNECTION_NAME); + EXPECT_EQ(connection_not_found, nullptr); + connection_not_found = connection_table_get_by_pair(conn_table_, &pair_); + EXPECT_EQ(connection_not_found, nullptr); +} + +TEST_F(ConnectionTableTest, PrintTable) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + + testing::internal::CaptureStdout(); + connection_table_print_by_pair(conn_table_); + std::string std_out = testing::internal::GetCapturedStdout(); + + ASSERT_NE(std_out, ""); + + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); +} + +TEST_F(ConnectionTableTest, AddMultipleConnections) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + + // Check connection table size + size_t conn_table_size = connection_table_len(conn_table_); + EXPECT_EQ(conn_table_size, (size_t)2); + + connection_t *c1 = connection_table_get_by_name(conn_table_, CONNECTION_NAME); + ASSERT_NE(c1, nullptr); + connection_t *c2 = + connection_table_get_by_name(conn_table_, CONNECTION_NAME_2); + ASSERT_NE(c2, nullptr); + EXPECT_NE(c1, c2); +} + +TEST_F(ConnectionTableTest, Iterate) { + connection_ = connection_table_allocate(conn_table_, &pair_, CONNECTION_NAME); + connection_->type = FACE_TYPE_TCP; + connection_->pair = pair_; + + // Insert an additional connection + address_pair_t pair_2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + connection_t *connection_2 = + connection_table_allocate(conn_table_, &pair_2, CONNECTION_NAME_2); + connection_2->type = FACE_TYPE_TCP; + connection_2->pair = pair_2; + + // Iterate over the connection table and count the connections + connection_t *c; + int count = 0; + connection_table_foreach(conn_table_, c, { count++; }); + EXPECT_EQ(count, 2); + + // Iterate over the connection table and check the connections + char local_addr_str[NI_MAXHOST], remote_addr_str[NI_MAXHOST]; + int local_port, remote_port; + testing::internal::CaptureStdout(); + connection_table_foreach(conn_table_, c, { + const address_pair_t *pair = connection_get_pair(c); + address_to_string(&pair->local, local_addr_str, &local_port); + address_to_string(&pair->remote, remote_addr_str, &remote_port); + + printf("%s:%d\t%s:%d\n", local_addr_str, local_port, remote_addr_str, + remote_port); + }); + + std::string std_out = testing::internal::GetCapturedStdout(); + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:3")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:4")); +} diff --git a/hicn-light/src/hicn/test/test-ctrl.cc b/hicn-light/src/hicn/test/test-ctrl.cc new file mode 100644 index 000000000..77b16a8af --- /dev/null +++ b/hicn-light/src/hicn/test/test-ctrl.cc @@ -0,0 +1,164 @@ +/* + * 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> + +extern "C" { +#include <hicn/util/log.h> +#include <hicn/ctrl.h> +#include <hicn/config/parse.h> +#include <hicn/ctrl/route.h> +#include <hicn/util/sstrncpy.h> +} + +class CtrlTest : public ::testing::Test { + protected: + CtrlTest() { + log_conf.log_level = LOG_INFO; + s_ = hc_sock_create_forwarder(HICNLIGHT_NG); + } + virtual ~CtrlTest() { hc_sock_free(s_); } + + hc_sock_t *s_ = nullptr; + hc_command_t command_ = {}; +}; + +/** + * The parse() function is used to easily create the command. + * Here we test the serialization of the commands i.e. from command + * to message sent to the forwarder. + */ + +TEST_F(CtrlTest, AddValidListener) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_TRUE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidProtocol) { + // Set invalid protocol (icmp) + std::string cmd = "add listener icmp udp0 10.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidLocalPort) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid port + command_.object.listener.local_port = 0; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidLocalAddress) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid family + command_.object.listener.family = -1; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerEmptyLocalAddress) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid address + command_.object.listener.local_addr = IP_ADDRESS_EMPTY; + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidSymbolicName) { + std::string cmd = "add listener udp 0udp 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidSymbolicName2) { + std::string cmd = "add listener udp udp! 10.0.0.1 9695 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddListenerInvalidInterfaceName) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth/0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_listener_create_conf(s_, &command_.object.listener); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddValidRoute) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_TRUE(success); +} + +TEST_F(CtrlTest, AddRouteInvalidLength) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid prfix len + command_.object.route.len = MAX_IPV6_PREFIX_LEN + 1; + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +} + +TEST_F(CtrlTest, AddRouteInvalidCost) { + std::string cmd = "add route conn0 c001::/64 1"; + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + + // Override with invalid cost + command_.object.route.cost = MAX_ROUTE_COST + 1; + + hc_result_t *result = hc_route_create_conf(s_, &command_.object.route); + bool success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); + + // Override with invalid cost + command_.object.route.cost = MIN_ROUTE_COST - 1; + + result = hc_route_create_conf(s_, &command_.object.route); + success = hc_result_get_success(s_, result); + EXPECT_FALSE(success); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-hash.cc b/hicn-light/src/hicn/test/test-hash.cc new file mode 100644 index 000000000..2b72e194a --- /dev/null +++ b/hicn-light/src/hicn/test/test-hash.cc @@ -0,0 +1,123 @@ +/* + * 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 <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +// #include <hicn/transport/utils/hash.h> + +extern "C" { +#include <hicn/base/hash.h> +#include <hicn/core/address_pair.h> +#include <hicn/core/listener.h> +} + +TEST(HashTest, MultipleHashesForSameAddrPair) { + address_pair_t pair = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + unsigned h1 = hash_struct(&pair); + unsigned h2 = hash_struct(&pair); + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, SameAddrPairs) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + address_pair_t pair2 = pair1; + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, DifferentAddrPairs) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(4)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameLocalDifferentRemote) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(4)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameRemoteDifferentLocal) { + address_pair_t pair1 = + address_pair_factory(_ADDRESS4_LOCALHOST(1), _ADDRESS4_LOCALHOST(2)); + + address_pair_t pair2 = + address_pair_factory(_ADDRESS4_LOCALHOST(3), _ADDRESS4_LOCALHOST(2)); + + unsigned h1 = hash_struct(&pair1); + unsigned h2 = hash_struct(&pair2); + EXPECT_NE(h1, h2); +} + +TEST(HashTest, SameAddresses) { + address_t addr1 = _ADDRESS4_LOCALHOST(1); + address_t addr2 = _ADDRESS4_LOCALHOST(1); + + unsigned h1 = hash_struct(&addr1); + unsigned h2 = hash_struct(&addr2); + + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, SameListenerKeys) { + listener_key_t key1 = + listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + listener_key_t key2 = + listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + + unsigned h1 = hash_struct(&key1); + unsigned h2 = hash_struct(&key2); + + EXPECT_EQ(h1, h2); +} + +TEST(HashTest, Collisions) { + uint32_t init_val = 2166136261UL; + (void)init_val; + + std::map<u32, uint32_t> hashes; + for (int i = 0; i < 50000; i++) { + uint32_t seg = i; + // u32 h = utils::hash::fnv32_buf (&seg, sizeof (seg)); + // u32 h = cumulative_hash32 (&seg, sizeof (seg), init_val); + u32 h = hash(&seg, sizeof(seg)); + EXPECT_FALSE(hashes.find(h) != hashes.end()) << seg << " - " << hashes[h]; + hashes[h] = seg; + } +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-khash.cc b/hicn-light/src/hicn/test/test-khash.cc new file mode 100644 index 000000000..4fcb48c31 --- /dev/null +++ b/hicn-light/src/hicn/test/test-khash.cc @@ -0,0 +1,154 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#include <hicn/base/khash.h> +} + +KHASH_MAP_INIT_INT(int, unsigned char) + +typedef struct { + unsigned key; + unsigned char val; +} int_unpack_t; + +typedef struct { + unsigned key; + unsigned char val; +} __attribute__((__packed__)) int_packed_t; + +#define hash_eq(a, b) ((a).key == (b).key) +#define hash_func(a) ((a).key) + +KHASH_INIT(iun, int_unpack_t, char, 0, hash_func, hash_eq) +KHASH_INIT(ipk, int_packed_t, char, 0, hash_func, hash_eq) + +class KHashTest : public ::testing::Test { + protected: + KHashTest() {} + + virtual ~KHashTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { khash = kh_init(int); } + + virtual void TearDown() { kh_destroy(int, khash); } + khash_t(int) * khash; +}; + +TEST_F(KHashTest, KhashIntSize) { + int ret; + int k; + int size = kh_size(khash); + + EXPECT_EQ(size, 0); + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 10; + } + size = kh_size(khash); + EXPECT_EQ(size, 1); +} + +TEST_F(KHashTest, KhashIntPut) { + int ret; + int k; + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 10; + } + int size = kh_size(khash); + EXPECT_EQ(size, 1); + k = kh_put(int, khash, 20, &ret); + if (ret == 1) { + kh_val(khash, k) = 20; + } + size = kh_size(khash); + EXPECT_EQ(size, 2); +} + +TEST_F(KHashTest, KhashCheckValue) { + int ret; + int k; + k = kh_put(int, khash, 10, &ret); + if (ret == 1) { + kh_val(khash, k) = 100; + } + k = kh_put(int, khash, 20, &ret); + if (ret == 1) { + kh_val(khash, k) = 200; + } + + k = kh_put(int, khash, 10, &ret); + int val = -1; + if (!ret) val = kh_val(khash, k); + EXPECT_EQ(val, 100); + + k = kh_put(int, khash, 20, &ret); + val = -1; + if (!ret) val = kh_val(khash, k); + EXPECT_EQ(val, 200); +} + +// Check that there are no collisions in case of same key hash +typedef struct { + int x; +} Key; +#define hash_key(key) 1 // Hash is always 1 to simulate collisions +#define key_hash_eq(a, b) (a->x == b->x) // Function used in case of collisions +KHASH_INIT(test_map, const Key *, unsigned, 1, hash_key, key_hash_eq); + +TEST_F(KHashTest, Collisions) { + int ret; + khiter_t k; + + kh_test_map_t *map = kh_init(test_map); + Key key1 = {.x = 10}; + Key key2 = {.x = 11}; + + k = kh_put_test_map(map, &key1, &ret); + EXPECT_EQ(ret, 1); + kh_val(map, k) = 15; + + k = kh_put_test_map(map, &key2, &ret); + EXPECT_EQ(ret, 1); + kh_val(map, k) = 27; + + k = kh_get_test_map(map, &key1); + ASSERT_NE(k, kh_end(map)); + unsigned val = kh_val(map, k); + EXPECT_EQ(val, 15u); + + k = kh_get_test_map(map, &key2); + ASSERT_NE(k, kh_end(map)); + val = kh_val(map, k); + EXPECT_EQ(val, 27u); + + kh_destroy_test_map(map); +} diff --git a/hicn-light/src/hicn/test/test-listener_table.cc b/hicn-light/src/hicn/test/test-listener_table.cc new file mode 100644 index 000000000..b2ed0c276 --- /dev/null +++ b/hicn-light/src/hicn/test/test-listener_table.cc @@ -0,0 +1,240 @@ +/* + * 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 <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/listener_table.h> +} + +#define LISTENER_NAME "listener_name_test" +#define LISTENER_NAME_2 "listener_name_test_2" + +class ListenerTableTest : public ::testing::Test { + protected: + ListenerTableTest() { + log_conf.log_level = LOG_INFO; + + listener_table_ = listener_table_create(); + key_ = listener_key_factory(_ADDRESS4_LOCALHOST(1), FACE_TYPE_UDP_LISTENER); + } + virtual ~ListenerTableTest() { listener_table_free(listener_table_); } + + listener_table_t *listener_table_; + listener_t *listener_; + listener_key_t key_; +}; + +TEST_F(ListenerTableTest, CreateTable) { + // Check listener_table allocation + EXPECT_NE(listener_table_, nullptr); + + // Check listener_table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)0); +} + +TEST_F(ListenerTableTest, AddListener) { + // Add listener to listener table + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)1); + EXPECT_NE(listener_, nullptr); + + // Get listener by name and by key + khiter_t k_name = kh_get_lt_name(listener_table_->id_by_name, LISTENER_NAME); + EXPECT_NE(k_name, kh_end(listener_table_->id_by_name)); + khiter_t k_key = kh_get_lt_key(listener_table_->id_by_key, &key_); + EXPECT_NE(k_key, kh_end(listener_table_->id_by_key)); +} + +TEST_F(ListenerTableTest, GetListener) { + // Add listener to listener table + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)1); + ASSERT_NE(listener_, nullptr); + + // Get listener by name + listener_t *listener_retrieved = + listener_table_get_by_name(listener_table_, LISTENER_NAME); + ASSERT_NE(listener_retrieved, nullptr); + EXPECT_EQ(listener_retrieved, listener_); + + // Get listener by key + listener_retrieved = listener_table_get_by_key(listener_table_, &key_); + ASSERT_NE(listener_retrieved, nullptr); + EXPECT_EQ(listener_retrieved, listener_); +} + +TEST_F(ListenerTableTest, GetListenerWithIdOutOfRange) { + listener_t *listener = _listener_table_get_by_id(listener_table_, ~0); + EXPECT_EQ(listener, nullptr); +} + +TEST_F(ListenerTableTest, GetListenerWithInvalidId) { + // First listener inserted has always id equal to 0 + int non_valid_id = 5; + + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + listener_t *listener_not_found = + listener_table_get_by_id(listener_table_, non_valid_id); + ASSERT_EQ(listener_not_found, nullptr); +} + +TEST_F(ListenerTableTest, GetListenerWithValidId) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_listener_id(listener_table_, listener_); + listener_t *listener_found = listener_table_get_by_id(listener_table_, id); + ASSERT_EQ(listener_found, listener_); +} + +TEST_F(ListenerTableTest, GetListenerIdFromValidName) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_id_by_name(listener_table_, LISTENER_NAME); + ASSERT_TRUE(listener_id_is_valid(id)); +} + +TEST_F(ListenerTableTest, GetListenerIdFromInvalidName) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + int id = listener_table_get_id_by_name(listener_table_, LISTENER_NAME_2); + ASSERT_FALSE(listener_id_is_valid(id)); +} + +TEST_F(ListenerTableTest, RemoveListener) { + // Add listener (listerner name and key must be set) + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + listener_->name = (char *)LISTENER_NAME; + listener_->key = key_; + + // Remove listener + int id = listener_table_get_listener_id(listener_table_, listener_); + listener_table_remove_by_id(listener_table_, id); + + // Check listener table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)0); + + // Check that previous listener is not valid anymore + listener_t *listener_not_found = + listener_table_get_by_id(listener_table_, id); + EXPECT_EQ(listener_not_found, nullptr); + listener_not_found = + listener_table_get_by_name(listener_table_, LISTENER_NAME); + EXPECT_EQ(listener_not_found, nullptr); + listener_not_found = listener_table_get_by_key(listener_table_, &key_); + EXPECT_EQ(listener_not_found, nullptr); +} + +TEST_F(ListenerTableTest, PrintTable) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + + testing::internal::CaptureStdout(); + listener_table_print_by_key(listener_table_); + std::string std_out = testing::internal::GetCapturedStdout(); + + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); +} + +TEST_F(ListenerTableTest, AddMultipleListeners) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + + // Check listener table size + size_t listener_table_size = listener_table_len(listener_table_); + EXPECT_EQ(listener_table_size, (size_t)2); + + listener_t *l1 = listener_table_get_by_name(listener_table_, LISTENER_NAME); + ASSERT_NE(l1, nullptr); + listener_t *l2 = listener_table_get_by_name(listener_table_, LISTENER_NAME_2); + ASSERT_NE(l2, nullptr); + EXPECT_NE(l1, l2); +} + +TEST_F(ListenerTableTest, Iterate) { + listener_ = listener_table_allocate(listener_table_, &key_, LISTENER_NAME); + listener_->type = FACE_TYPE_UDP_LISTENER; + listener_->key = key_; + + // Insert an additional listener + listener_key_t key_2 = + listener_key_factory(_ADDRESS4_LOCALHOST(2), FACE_TYPE_TCP_LISTENER); + listener_t *listener_2 = + listener_table_allocate(listener_table_, &key_2, LISTENER_NAME_2); + listener_2->type = FACE_TYPE_UDP_LISTENER; + listener_2->key = key_2; + + // Iterate over the listener table and count the listeners + listener_t *l; + int count = 0; + listener_table_foreach(listener_table_, l, { count++; }); + EXPECT_EQ(count, 2); + + // Iterate over the listener table and check the listeners + char addr_str[NI_MAXHOST]; + int port; + testing::internal::CaptureStdout(); + listener_table_foreach(listener_table_, l, { + address_to_string(&l->address, addr_str, &port); + printf("%s\t%s:%d\n", face_type_str(l->type), addr_str, port); + }); + + std::string std_out = testing::internal::GetCapturedStdout(); + ASSERT_NE(std_out, ""); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:1")); + EXPECT_THAT(std_out, testing::HasSubstr("127.0.0.1:2")); + EXPECT_THAT(std_out, testing::HasSubstr("UDP")); + EXPECT_THAT(std_out, testing::HasSubstr("TCP")); +} diff --git a/hicn-light/src/hicn/test/test-local_prefixes.cc b/hicn-light/src/hicn/test/test-local_prefixes.cc new file mode 100644 index 000000000..80eb46501 --- /dev/null +++ b/hicn-light/src/hicn/test/test-local_prefixes.cc @@ -0,0 +1,229 @@ +/* + * 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 <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <arpa/inet.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/strategies/local_prefixes.h> +#include <hicn/core/strategy.h> +#include <hicn/core/name.h> +} + +const char *name_str1 = "b001::0"; +const char *name_str2 = "b002::0"; +const char *name_str3 = "b003::0"; +const char *name_str4 = "b004::0"; +const char *name_str5 = "b005::0"; +const char *name_str6 = "b006::0"; +const char *name_str7 = "b007::0"; +const char *name_str8 = "b008::0"; +const char *name_str9 = "b009::0"; +const char *name_str10 = "b010::0"; +const char *name_str11 = "b011::0"; + +class LocalPrefixesTest : public ::testing::Test { + protected: + LocalPrefixesTest() {} + + virtual ~LocalPrefixesTest() {} +}; + +TEST_F(LocalPrefixesTest, LocalPrefixesAddName) { + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + ip_address_t result; + inet_pton(AF_INET6, name_str1, (struct in6_addr *)&result); + Name name1; + name_CreateFromAddress(&name1, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str2, (struct in6_addr *)&result); + Name name2; + name_CreateFromAddress(&name2, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str3, (struct in6_addr *)&result); + Name name3; + name_CreateFromAddress(&name3, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str4, (struct in6_addr *)&result); + Name name4; + name_CreateFromAddress(&name4, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str5, (struct in6_addr *)&result); + Name name5; + name_CreateFromAddress(&name5, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str6, (struct in6_addr *)&result); + Name name6; + name_CreateFromAddress(&name6, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str7, (struct in6_addr *)&result); + Name name7; + name_CreateFromAddress(&name7, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str8, (struct in6_addr *)&result); + Name name8; + name_CreateFromAddress(&name8, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str9, (struct in6_addr *)&result); + Name name9; + name_CreateFromAddress(&name9, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str10, (struct in6_addr *)&result); + Name name10; + name_CreateFromAddress(&name10, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str11, (struct in6_addr *)&result); + Name name11; + name_CreateFromAddress(&name11, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp, &name1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)1); + + local_prefixes_add_prefix(lp, &name1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)1); + + local_prefixes_add_prefix(lp, &name2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)2); + + local_prefixes_add_prefix(lp, &name2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)2); + + local_prefixes_add_prefix(lp, &name3); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)3); + + local_prefixes_add_prefix(lp, &name4); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_add_prefix(lp, &name5); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)5); + + local_prefixes_add_prefix(lp, &name6); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)6); + + local_prefixes_add_prefix(lp, &name7); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)7); + + local_prefixes_add_prefix(lp, &name8); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)8); + + local_prefixes_add_prefix(lp, &name9); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)9); + + local_prefixes_add_prefix(lp, &name10); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + local_prefixes_add_prefix(lp, &name11); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + free_local_prefixes(lp); +} + +TEST_F(LocalPrefixesTest, LocalPrefixesAddPrefixes) { + local_prefixes_t *lp = create_local_prefixes(); + EXPECT_FALSE(lp == nullptr); + + ip_address_t result; + + local_prefixes_t *lp1 = create_local_prefixes(); + EXPECT_FALSE(lp1 == nullptr); + + inet_pton(AF_INET6, name_str1, (struct in6_addr *)&result); + Name name1; + name_CreateFromAddress(&name1, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str2, (struct in6_addr *)&result); + Name name2; + name_CreateFromAddress(&name2, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str3, (struct in6_addr *)&result); + Name name3; + name_CreateFromAddress(&name3, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str4, (struct in6_addr *)&result); + Name name4; + name_CreateFromAddress(&name4, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp1, &name1); + local_prefixes_add_prefix(lp1, &name2); + local_prefixes_add_prefix(lp1, &name3); + local_prefixes_add_prefix(lp1, &name4); + + EXPECT_EQ(local_prefixes_get_len(lp1), (unsigned)4); + + local_prefixes_add_prefixes(lp, lp1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_add_prefixes(lp, lp1); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)4); + + local_prefixes_t *lp2 = create_local_prefixes(); + EXPECT_FALSE(lp2 == nullptr); + + inet_pton(AF_INET6, name_str5, (struct in6_addr *)&result); + Name name5; + name_CreateFromAddress(&name5, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str6, (struct in6_addr *)&result); + Name name6; + name_CreateFromAddress(&name6, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str7, (struct in6_addr *)&result); + Name name7; + name_CreateFromAddress(&name7, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str8, (struct in6_addr *)&result); + Name name8; + name_CreateFromAddress(&name8, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str9, (struct in6_addr *)&result); + Name name9; + name_CreateFromAddress(&name9, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str10, (struct in6_addr *)&result); + Name name10; + name_CreateFromAddress(&name10, AF_INET6, result, 128); + + inet_pton(AF_INET6, name_str11, (struct in6_addr *)&result); + Name name11; + name_CreateFromAddress(&name11, AF_INET6, result, 128); + + local_prefixes_add_prefix(lp2, &name5); + local_prefixes_add_prefix(lp2, &name6); + local_prefixes_add_prefix(lp2, &name7); + local_prefixes_add_prefix(lp2, &name8); + local_prefixes_add_prefix(lp2, &name9); + local_prefixes_add_prefix(lp2, &name10); + local_prefixes_add_prefix(lp2, &name11); + + EXPECT_EQ(local_prefixes_get_len(lp2), (unsigned)7); + + local_prefixes_add_prefixes(lp, lp2); + EXPECT_EQ(local_prefixes_get_len(lp), (unsigned)10); + + free_local_prefixes(lp); + free_local_prefixes(lp1); + free_local_prefixes(lp2); +} diff --git a/hicn-light/src/hicn/test/test-loop.cc b/hicn-light/src/hicn/test/test-loop.cc new file mode 100644 index 000000000..f783b0ada --- /dev/null +++ b/hicn-light/src/hicn/test/test-loop.cc @@ -0,0 +1,288 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> +#include <fcntl.h> + +extern "C" { +#include <hicn/base/loop.h> +} + +class LoopTest : public ::testing::Test { + static constexpr uint16_t BUFFER_SIZE = 1024; + + protected: + LoopTest() + : server_port_(9191), + loop_(nullptr), + timer_tick_(2000), + connection_socket_(-1), + event_(nullptr), + timer_(nullptr) {} + + virtual ~LoopTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + static int onFirstTimerExpiration(void *owner, int fd, void *arg) { + std::cout << "This function should never be called" << std::endl; + EXPECT_TRUE(false); + return -1; + } + + static int onSecondTimerExpiration(void *owner, int fd, void *arg) { + std::cout << "First timer expired. Cancel second timer." << std::endl; + LoopTest *test = (LoopTest *)(arg); + loop_event_unregister(test->timer_); + return 0; + } + + static int onTimerExpiration(void *owner, int fd, void *arg) { + // Create client socket + struct sockaddr_in addr; + int client_socket; + LoopTest *test = (LoopTest *)(arg); + + client_socket = socket(AF_INET, SOCK_STREAM, 0); + if (client_socket == -1) { + perror("socket"); + return -1; + } + + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_family = AF_INET; + addr.sin_port = htons(test->server_port_); + + if (connect(client_socket, (struct sockaddr *)&addr, + sizeof(struct sockaddr)) == -1) { + perror("connect"); + return -1; + } + + if (send(client_socket, "Hello, world!\n", 14, 0) == -1) { + perror("send"); + return -1; + } + + close(client_socket); + loop_event_unregister(test->timer_); + + return 0; + } + + static int onNewConnection(void *owner, int fd, void *arg) { + LoopTest *test = (LoopTest *)arg; + struct sockaddr_in addr; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + + socklen_t addr_len = sizeof(struct sockaddr_in); + int ret; + + int client_fd = + accept(test->connection_socket_, (struct sockaddr *)(&addr), &addr_len); + if (client_fd == -1) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "accept failed"); + } + + perror("accept"); + return -1; + } + + // Read whatever data available and close connection. + ret = read(client_fd, test->buffer, BUFFER_SIZE); + if (ret < 0) { + perror("read"); + return -1; + } + + test->buffer[ret] = '\0'; + std::cout << "Received: " << (char *)test->buffer << std::endl; + + close(client_fd); + loop_event_unregister(test->event_); + + return 0; + } + + void createTcpSocketServer() { + struct sockaddr_in addr; + int ret; + + /* Create local socket. */ + + connection_socket_ = socket(AF_INET, SOCK_STREAM, 0); + if (connection_socket_ == -1) { + perror("socket"); + return; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(server_port_); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(connection_socket_, (const struct sockaddr *)&addr, + sizeof(struct sockaddr_in)); + if (ret == -1) { + perror("bind"); + return; + } + + ret = listen(connection_socket_, 20); + if (ret == -1) { + perror("listen"); + return; + } + } + + uint16_t server_port_; + loop_t *loop_; + unsigned timer_tick_; + int connection_socket_; + event_t *event_; + event_t *timer_; + char buffer[BUFFER_SIZE]; +}; + +TEST_F(LoopTest, LoopCreateAndFree) { + loop_ = loop_create(); + EXPECT_TRUE(loop_ != NULL); + loop_free(loop_); + EXPECT_TRUE(loop_ != NULL); +} + +TEST_F(LoopTest, EventCreateAndFree) { + int ret; + + // Fake fd + int fd = socket(AF_INET, SOCK_STREAM, 0); + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, fd, nullptr, + &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + // Register the event + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Unregister the event + ret = loop_event_free(event_); + EXPECT_TRUE(ret >= 0); + + // close fd + ret = close(fd); + EXPECT_EQ(ret, 0); + + // Free event loop + loop_free(loop_); +} + +TEST_F(LoopTest, TimerCreateAndCancel) { + int ret; + event_t *timer2; + loop_ = loop_create(); + + ret = loop_timer_create(&timer_, loop_, nullptr, + &LoopTest::onFirstTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_create(&timer2, loop_, nullptr, + &LoopTest::onSecondTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer2); + + // Register the 1st timer + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Register the 2nd timer + ret = loop_timer_register(timer2, timer_tick_ / 2); + EXPECT_TRUE(ret >= 0); + + _loop_dispatch(loop_, 0); + + loop_undispatch(loop_); + + // Unregister the events + ret = loop_event_free(timer_); + ret += loop_event_free(timer2); + EXPECT_TRUE(ret >= 0); + + // Free event loop + loop_free(loop_); +} + +TEST_F(LoopTest, LoopDispatch) { + int ret; + + // Create new unix socket + createTcpSocketServer(); + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, connection_socket_, nullptr, + &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Create timer. + ret = loop_timer_create(&timer_, loop_, nullptr, &LoopTest::onTimerExpiration, + this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Start event dispatching + _loop_dispatch(loop_, 0); + + // Stop dispatching + loop_undispatch(loop_); + + // Free events + loop_event_free(timer_); + loop_event_free(event_); + + // Free event loop + loop_free(loop_); +} diff --git a/hicn-light/src/hicn/test/test-msgbuf_pool.cc b/hicn-light/src/hicn/test/test-msgbuf_pool.cc new file mode 100644 index 000000000..5537aa216 --- /dev/null +++ b/hicn-light/src/hicn/test/test-msgbuf_pool.cc @@ -0,0 +1,191 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/msgbuf_pool.h> +#include <hicn/base/pool.h> +} + +class MsgbufPoolTest : public ::testing::Test { + protected: + MsgbufPoolTest() { msgbuf_pool = msgbuf_pool_create(); } + virtual ~MsgbufPoolTest() { msgbuf_pool_free(msgbuf_pool); } + + msgbuf_pool_t *msgbuf_pool; +}; + +TEST_F(MsgbufPoolTest, Create) { + /* Check msgbuf_pool allocation */ + EXPECT_NE(msgbuf_pool, nullptr); + + /* Check msgbuf_pool size */ + size_t msgbuf_pool_size = pool_hdr(msgbuf_pool->buffers)->alloc_size; + EXPECT_EQ(msgbuf_pool_size, (size_t)PACKET_POOL_DEFAULT_INIT_SIZE); +} + +TEST_F(MsgbufPoolTest, GetMsgbuf) { + msgbuf_t *msgbuf = NULL; + + /* Get valid msgbuf from msgbuf_pool */ + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + /* Check if the returned id is correct */ + off_t id = msgbuf_pool_get_id(msgbuf_pool, msgbuf); + EXPECT_EQ(id, msgbuf_id); + + /* Check if the returned msgbuf is correct */ + msgbuf_t *msgbuf_retrieved = msgbuf_pool_at(msgbuf_pool, id); + EXPECT_EQ(msgbuf_retrieved, msgbuf); +} + +TEST_F(MsgbufPoolTest, PutMsgbuf) { + /* Check that asking a msgbuf right after releasing another one + returns the same msgbuf */ + + msgbuf_t *msgbuf = NULL; + + off_t id1 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + msgbuf_pool_put(msgbuf_pool, msgbuf); + + off_t id2 = msgbuf_pool_get(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + + EXPECT_EQ(id2, id1); +} + +TEST_F(MsgbufPoolTest, GetMultipleMsgbufs) { + const int NUM_MSG = 3; + msgbuf_t *msgbufs[NUM_MSG]; + + /* Check if successful allocation */ + int ret = msgbuf_pool_getn(msgbuf_pool, msgbufs, NUM_MSG); + EXPECT_EQ(ret, 0); + + /* Check if all msgbufs are valid */ + for (unsigned i = 0; i < NUM_MSG; i++) { + msgbuf_pool_get_id(msgbuf_pool, msgbufs[i]); + EXPECT_NE(msgbufs[i], nullptr) << "Invalid index: " << i; + } +} + +TEST_F(MsgbufPoolTest, AcquireMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf + msgbuf_pool_acquire(msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 1u); + + msgbuf_pool_acquire(msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 2u); +} + +TEST_F(MsgbufPoolTest, ReleaseMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf + msgbuf_pool_acquire(msgbuf); + EXPECT_EQ(msgbuf->refs, 1u); + + // Release the msgbuf + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_EQ(msgbuf, nullptr); +} + +TEST_F(MsgbufPoolTest, ReleaseNotAcquiredMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get valid msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + +#ifndef NDEBUG + // Release the msgbuf even if it is not been acquired + ASSERT_DEATH( + { + msgbuf_pool_release(msgbuf_pool, &msgbuf); + ; + }, + ".*Assertion.*"); +#endif +} + +TEST_F(MsgbufPoolTest, MultipleAcquireAndReleaseMsgbuf) { + msgbuf_t *msgbuf = NULL; + + // Get msgbuf from msgbuf_pool + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + // Acquire the msgbuf multiple times + msgbuf_pool_acquire(msgbuf); + msgbuf_pool_acquire(msgbuf); + EXPECT_EQ(msgbuf->refs, 2u); + + // Release the msgbuf + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_NE(msgbuf, nullptr); + EXPECT_EQ(msgbuf->refs, 1u); + msgbuf_pool_release(msgbuf_pool, &msgbuf); + EXPECT_EQ(msgbuf, nullptr); +} + +TEST_F(MsgbufPoolTest, CloneMsgbuf) { + msgbuf_t *msgbuf = NULL; + off_t msgbuf_id = msgbuf_pool_get(msgbuf_pool, &msgbuf); + msgbuf->type = MSGBUF_TYPE_COMMAND; + EXPECT_NE(msgbuf, nullptr); + EXPECT_NE(msgbuf_id_is_valid((unsigned long)msgbuf_id), 0); + + msgbuf_t *new_msgbuf; + off_t new_msg_id = msgbuf_pool_clone(msgbuf_pool, &new_msgbuf, msgbuf_id); + + EXPECT_EQ(new_msgbuf, msgbuf_pool_at(msgbuf_pool, new_msg_id)); + EXPECT_NE(new_msgbuf, msgbuf_pool_at(msgbuf_pool, msgbuf_id)); + EXPECT_NE(new_msgbuf, msgbuf); + EXPECT_TRUE(memcmp(msgbuf, new_msgbuf, sizeof(msgbuf_t)) == 0); +} diff --git a/hicn-light/src/hicn/test/test-nexthops.cc b/hicn-light/src/hicn/test/test-nexthops.cc new file mode 100644 index 000000000..9063298fd --- /dev/null +++ b/hicn-light/src/hicn/test/test-nexthops.cc @@ -0,0 +1,274 @@ +/* + * 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 <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/nexthops.h> +#include <hicn/core/strategy.h> +} + +#define NEXTHOP1 50 +#define NEXTHOP2 51 +#define NEXTHOP3 52 + +class NexthopsTest : public ::testing::Test { + protected: + NexthopsTest() {} + + virtual ~NexthopsTest() {} + + nexthops_t nexthops; +}; + +TEST_F(NexthopsTest, NexthopsAdd) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsRemove) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP2); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 2); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP3); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP3); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_remove(&nexthops, NEXTHOP1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 0); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsClear) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_clear(&nexthops); + + EXPECT_TRUE(nexthops_get_len(&nexthops) == 0); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsGetOne) { + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + unsigned nexthop = nexthops_get_one(&nexthops); + + EXPECT_TRUE(nexthops_contains(&nexthops, nexthop)); +} + +TEST_F(NexthopsTest, NexthopsSelect) { + int ret; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + ret = nexthops_select(&nexthops, 2); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 0); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + nexthops_reset(&nexthops); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 4); + + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_select(&nexthops, 3); + + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 3); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsDisable) { + int ret; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + + ret = nexthops_disable(&nexthops, 0); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 2); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_disable(&nexthops, 2); + + EXPECT_TRUE(ret == 0); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); + + ret = nexthops_disable(&nexthops, 3); + EXPECT_TRUE(ret == -1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 3); + EXPECT_TRUE(nexthops_get_curlen(&nexthops) == 1); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP3)); +} + +TEST_F(NexthopsTest, NexthopsState) { + strategy_nexthop_state_t state; + nexthops = NEXTHOPS_EMPTY; + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP2); + nexthops_add(&nexthops, NEXTHOP3); + nexthops.state[0].load_balancer.pi = 100; + nexthops.state[1].load_balancer.pi = 200; + nexthops.state[2].load_balancer.pi = 300; + + state = nexthops_state(&nexthops, 0); + EXPECT_TRUE(state.load_balancer.pi == 100); + + state = nexthops_state(&nexthops, 1); + EXPECT_TRUE(state.load_balancer.pi == 200); + + state = nexthops_state(&nexthops, 2); + EXPECT_TRUE(state.load_balancer.pi == 300); + + nexthops_remove(&nexthops, NEXTHOP1); + EXPECT_TRUE(nexthops_get_len(&nexthops) == 2); + EXPECT_FALSE(nexthops_contains(&nexthops, NEXTHOP1)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP2)); + EXPECT_TRUE(nexthops_contains(&nexthops, NEXTHOP3)); + + state = nexthops_state(&nexthops, 0); + EXPECT_TRUE(state.load_balancer.pi == 300); + + state = nexthops_state(&nexthops, 1); + EXPECT_TRUE(state.load_balancer.pi == 200); +} + +TEST_F(NexthopsTest, NexthopsEqual) { + nexthops = NEXTHOPS_EMPTY; + nexthops_t nexthops_eq = NEXTHOPS_EMPTY; + nexthops_t nexthops_not_eq = NEXTHOPS_EMPTY; + + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP3); + nexthops_add(&nexthops_eq, NEXTHOP1); + nexthops_add(&nexthops_eq, NEXTHOP3); + nexthops_add(&nexthops_not_eq, NEXTHOP2); + + bool ret = nexthops_equal(&nexthops, &nexthops_eq); + EXPECT_TRUE(ret); + + ret = nexthops_equal(&nexthops, &nexthops_not_eq); + EXPECT_FALSE(ret); +} + +TEST_F(NexthopsTest, NexthopsCopy) { + nexthops = NEXTHOPS_EMPTY; + nexthops_t nexthops_eq = NEXTHOPS_EMPTY; + + nexthops_add(&nexthops, NEXTHOP1); + nexthops_add(&nexthops, NEXTHOP3); + nexthops_copy(&nexthops, &nexthops_eq); + + bool ret = nexthops_equal(&nexthops, &nexthops_eq); + EXPECT_TRUE(ret); +} diff --git a/hicn-light/src/hicn/test/test-packet_cache.cc b/hicn-light/src/hicn/test/test-packet_cache.cc new file mode 100644 index 000000000..bb24daeb8 --- /dev/null +++ b/hicn-light/src/hicn/test/test-packet_cache.cc @@ -0,0 +1,524 @@ +/* + * 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 <thread> +#include <optional> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/packet_cache.h> +} + +const unsigned CS_SIZE = 100; +const unsigned CONN_ID = 0; +const unsigned CONN_ID_2 = 1; +const unsigned MSGBUF_ID = 0; +const unsigned MSGBUF_ID_2 = 1; +const unsigned MSGBUF_ID_3 = 2; +const unsigned FIVE_SECONDS = 5000; +const unsigned IPV4_LEN = 32; +const unsigned IPV6_LEN = 128; + +class PacketCacheTest : public ::testing::Test { + protected: + PacketCacheTest() { + pkt_cache = pkt_cache_create(CS_SIZE); + name = (Name *)malloc(sizeof(Name)); + name_CreateFromAddress(name, AF_INET, IPV4_ANY, IPV4_LEN); + msgbuf_pool = msgbuf_pool_create(); + } + virtual ~PacketCacheTest() { + pkt_cache_free(pkt_cache); + msgbuf_pool_free(msgbuf_pool); + } + + pkt_cache_t *pkt_cache; + pkt_cache_entry_t *entry = nullptr; + msgbuf_pool_t *msgbuf_pool; + Name *name; +}; + +msgbuf_t *msgbuf_factory(msgbuf_pool_t *msgbuf_pool, unsigned conn_id, + Name *name, + std::optional<Ticks> lifetime = FIVE_SECONDS) { + msgbuf_t *msgbuf; + msgbuf_pool_get(msgbuf_pool, &msgbuf); + + msgbuf->connection_id = conn_id; + name_Copy(name, msgbuf_get_name(msgbuf)); + hicn_packet_init_header(HF_INET6_TCP, + (hicn_header_t *)msgbuf_get_packet(msgbuf)); + // Same as 'msgbuf_set_data_expiry_time', + // it would write in the same field + msgbuf_set_interest_lifetime(msgbuf, *lifetime); + + return msgbuf; +} + +TEST_F(PacketCacheTest, CreatePacketCache) { + // Check packet cache allocation + EXPECT_NE(pkt_cache, nullptr); + pit_t *pit = pkt_cache_get_pit(pkt_cache); + ASSERT_NE(pit, nullptr); + cs_t *cs = pkt_cache_get_cs(pkt_cache); + ASSERT_NE(cs, nullptr); + + // Check sizes + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); +} + +TEST_F(PacketCacheTest, AddPacketCacheEntry) { + // Add entry to the packet cache + entry = pkt_cache_allocate(pkt_cache, name); + EXPECT_NE(entry, nullptr); + ASSERT_EQ(pkt_cache_get_size(pkt_cache), 1u); + + // // Get entry by name + Name name_key = name_key_factory(name); + khiter_t k = kh_get_pkt_cache_name(pkt_cache->index_by_name, &name_key); + EXPECT_NE(k, kh_end(pkt_cache->index_by_name)); +} + +TEST_F(PacketCacheTest, GetCS) { + cs_t *cs = pkt_cache_get_cs(pkt_cache); + ASSERT_NE(cs, nullptr); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + EXPECT_EQ(cs->type, CS_TYPE_LRU); + EXPECT_EQ(cs->num_entries, 0); + EXPECT_EQ(cs->lru.head, (off_t)INVALID_ENTRY_ID); + EXPECT_EQ(cs->lru.tail, (off_t)INVALID_ENTRY_ID); +} + +TEST_F(PacketCacheTest, GetPIT) { + pit_t *pit = pkt_cache_get_pit(pkt_cache); + ASSERT_NE(pit, nullptr); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); +} + +TEST_F(PacketCacheTest, LookupEmpty) { + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *entry = pkt_cache_lookup(pkt_cache, name, msgbuf_pool, + &lookup_result, &entry_id, true); + + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(entry, nullptr); +} + +TEST_F(PacketCacheTest, AddEntryAndLookup) { + // Add entry to the packet cache + entry = pkt_cache_allocate(pkt_cache, name); + entry->entry_type = PKT_CACHE_PIT_TYPE; + ASSERT_NE(entry, nullptr); + + // Perform lookup + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + + EXPECT_TRUE(lookup_result == PKT_CACHE_LU_INTEREST_NOT_EXPIRED || + lookup_result == PKT_CACHE_LU_INTEREST_EXPIRED); + EXPECT_NE(lu_entry, nullptr); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, AddToPIT) { + // Prepare msgbuf + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + + // Check if entry properly created + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, AddToCS) { + // Prepare msgbuf + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + + // Check if entry properly created + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + EXPECT_EQ(cs->num_entries, 1); + EXPECT_EQ(cs->lru.head, entry_id); + EXPECT_EQ(cs->lru.tail, entry_id); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, PitToCS) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if entry properly updated + pkt_cache_pit_to_cs(pkt_cache, entry, msgbuf_pool, msgbuf, MSGBUF_ID, + entry_id); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + EXPECT_EQ(cs->num_entries, 1); + EXPECT_EQ(cs->lru.head, entry_id); + EXPECT_EQ(cs->lru.tail, entry_id); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, CsToPIT) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if entry properly updated + pkt_cache_cs_to_pit(pkt_cache, entry, msgbuf_pool, msgbuf, MSGBUF_ID, + entry_id); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, UpdateInPIT) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly updated + pkt_cache_update_pit(pkt_cache, entry, new_msgbuf); + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_EQ(pit_entry_ingress_contains(&entry->u.pit_entry, CONN_ID_2), true); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, UpdateInCS) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + off_t entry_id = pkt_cache_get_entry_id(pkt_cache, entry); + + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly updated + pkt_cache_update_cs(pkt_cache, msgbuf_pool, entry, new_msgbuf, MSGBUF_ID_2); + cs_entry_t *cs_entry = &entry->u.cs_entry; + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_CS_TYPE); + EXPECT_EQ(cs_entry->msgbuf_id, MSGBUF_ID_2); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, RemoveFromPIT) { + // Prepare msgbuf and PIT entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 1u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + pkt_cache_pit_remove_entry(pkt_cache, entry, name); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(lu_entry, nullptr); +} + +TEST_F(PacketCacheTest, RemoveFromCS) { + // Prepare msgbuf and CS entry + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 1u); + + pkt_cache_cs_remove_entry(pkt_cache, entry, msgbuf_pool, false); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 0u); + + // Check if CS properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + EXPECT_EQ(cs->num_entries, 0); + EXPECT_EQ(cs->lru.head, (off_t)INVALID_ENTRY_ID); + EXPECT_EQ(cs->lru.tail, (off_t)INVALID_ENTRY_ID); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_NONE); + EXPECT_EQ(lu_entry, nullptr); +} + +TEST_F(PacketCacheTest, AddTwoEntriesToCS) { + // Prepare msgbufs + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + pkt_cache_entry_t *entry_1 = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + pkt_cache_entry_t *entry_2 = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, new_msgbuf, MSGBUF_ID_2); + off_t entry_id_1 = pkt_cache_get_entry_id(pkt_cache, entry_1); + off_t entry_id_2 = pkt_cache_get_entry_id(pkt_cache, entry_2); + + // Check if the CS and LRU cache are properly updated + cs_t *cs = pkt_cache_get_cs(pkt_cache); + EXPECT_EQ(cs->num_entries, 2); + EXPECT_EQ(cs->lru.head, entry_id_2); + EXPECT_EQ(cs->lru.tail, entry_id_1); + ASSERT_EQ(pkt_cache_get_pit_size(pkt_cache), 0u); + ASSERT_EQ(pkt_cache_get_cs_size(pkt_cache), 2u); +} + +TEST_F(PacketCacheTest, AggregateInPIT) { + // Prepare msgbufs + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID_2, &new_name); + + // Check if entry properly created (use sleep to get an updated ts) + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + Ticks old_lifetime = entry->expire_ts; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bool is_aggregated = + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + Ticks new_lifetime = entry->expire_ts; + + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_GT(new_lifetime, old_lifetime); + ASSERT_EQ(is_aggregated, true); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, RetransmissionInPIT) { + // Prepare msgbufs (using same connection ID) + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name); + Name new_name; + name_CreateFromAddress(&new_name, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *new_msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, &new_name); + + // Check if entry properly created (use sleep to get an updated ts) + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + Ticks old_lifetime = entry->expire_ts; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bool is_aggregated = + pkt_cache_try_aggregate_in_pit(pkt_cache, entry, new_msgbuf); + Ticks new_lifetime = entry->expire_ts; + + ASSERT_NE(entry, nullptr); + EXPECT_EQ(entry->entry_type, PKT_CACHE_PIT_TYPE); + EXPECT_GT(new_lifetime, old_lifetime); + ASSERT_EQ(is_aggregated, false); + + // Check if hashtable correctly updated + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_entry_t *lu_entry = pkt_cache_lookup( + pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_NOT_EXPIRED); + EXPECT_EQ(lu_entry, entry); +} + +TEST_F(PacketCacheTest, LookupExpiredInterest) { + // Prepare msgbuf with 0 as interest lifetime + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + + // Add to PIT + pkt_cache_entry_t *entry = pkt_cache_add_to_pit(pkt_cache, msgbuf); + ASSERT_NE(entry, nullptr); + + // Wait to make the interest expire + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, + true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_INTEREST_EXPIRED); +} + +TEST_F(PacketCacheTest, LookupExpiredData) { + // Prepare msgbuf with 0 as data expiry time + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + + // Add to CS + pkt_cache_entry_t *entry = + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + ASSERT_NE(entry, nullptr); + + // Wait to make the interest expire + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + pkt_cache_lookup_t lookup_result; + off_t entry_id; + pkt_cache_lookup(pkt_cache, name, msgbuf_pool, &lookup_result, &entry_id, + true); + EXPECT_EQ(lookup_result, PKT_CACHE_LU_DATA_EXPIRED); +} + +TEST_F(PacketCacheTest, GetStaleEntries) { + // Add to CS a msgbuf with immediate expiration (i.e. stale) + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, CONN_ID, name, 0); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, MSGBUF_ID); + + // Add to CS another msgbuf with immediate expiration (i.e. stale) + Name name_2; + name_CreateFromAddress(&name_2, AF_INET, IPV4_LOOPBACK, IPV4_LEN); + msgbuf_t *msgbuf_2 = msgbuf_factory(msgbuf_pool, CONN_ID, &name_2, 0); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_2, MSGBUF_ID_2); + + // Add to CS a msgbuf with 5-seconds expiration (i.e. not stale) + Name name_3; + name_CreateFromAddress(&name_3, AF_INET6, IPV6_LOOPBACK, IPV6_LEN); + msgbuf_t *msgbuf_3 = + msgbuf_factory(msgbuf_pool, CONN_ID, &name_3, FIVE_SECONDS); + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf_3, MSGBUF_ID_3); + + size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); + EXPECT_EQ(num_stale_entries, 2u); +} + +TEST_F(PacketCacheTest, GetMultipleStaleEntries) { + ip_address_t addr; + char name[30]; + const int NUM_STALES = 10; + + // Add to CS multiple msgbufs with immediate expiration (i.e. 0 seconds), + // resulting in stale entries + for (int i = 0; i < NUM_STALES; i++) { + snprintf(name, 30, "b001::%d", i); + inet_pton(AF_INET6, name, (struct in6_addr *)&addr); + Name name; + name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, 0); + + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); + } + + // Add to CS multiple msgbufs with 5-seconds expiration, + // resulting in non-stale entries + for (int i = NUM_STALES; i < 15; i++) { + snprintf(name, 30, "b001::%d", i); + inet_pton(AF_INET6, name, (struct in6_addr *)&addr); + Name name; + name_CreateFromAddress(&name, AF_INET6, addr, IPV6_LEN); + msgbuf_t *msgbuf = msgbuf_factory(msgbuf_pool, i, &name, FIVE_SECONDS); + + pkt_cache_add_to_cs(pkt_cache, msgbuf_pool, msgbuf, i); + } + + size_t num_stale_entries = pkt_cache_get_num_cs_stale_entries(pkt_cache); + EXPECT_EQ(num_stale_entries, (size_t)NUM_STALES); +} diff --git a/hicn-light/src/hicn/test/test-parser.cc b/hicn-light/src/hicn/test/test-parser.cc new file mode 100644 index 000000000..3a8d2cdb2 --- /dev/null +++ b/hicn-light/src/hicn/test/test-parser.cc @@ -0,0 +1,71 @@ +/* + * 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> + +extern "C" { +#include <hicn/util/log.h> +#include <hicn/config/parse.h> +} + +class ParserTest : public ::testing::Test { + protected: + ParserTest() { log_conf.log_level = LOG_INFO; } + virtual ~ParserTest() {} + + hc_command_t command_ = {}; +}; + +TEST_F(ParserTest, AddValidListener) { + std::string cmd = "add listener udp udp0 10.0.0.1 9695 eth0"; + + ASSERT_EQ(parse(cmd.c_str(), &command_), 0); + EXPECT_EQ(command_.object.listener.type, FACE_TYPE_UDP_LISTENER); + EXPECT_EQ(std::string(command_.object.listener.name), "udp0"); + EXPECT_EQ(command_.object.listener.family, AF_INET); + EXPECT_EQ(command_.object.listener.local_port, 9695); + EXPECT_EQ(std::string(command_.object.listener.interface_name), "eth0"); +} + +TEST_F(ParserTest, AddListenerSymbolicOverflow) { + std::string cmd = + "add listener udp super-long-symbolic-name 10.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidAddress) { + std::string cmd = "add listener udp udp0 10.0.0.0.1 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidAddressString) { + std::string cmd = "add listener udp udp0 invalid-addr 9696 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidPortOutsideRange) { + std::string cmd = "add listener udp udp0 10.0.0.1 0 eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, AddListenerInvalidPortString) { + std::string cmd = "add listener udp udp0 10.0.0.1 invalid-port eth0"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +} + +TEST_F(ParserTest, UnknownCommnad) { + std::string cmd = "add face"; + ASSERT_EQ(parse(cmd.c_str(), &command_), -1); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-pool.cc b/hicn-light/src/hicn/test/test-pool.cc new file mode 100644 index 000000000..c631415ca --- /dev/null +++ b/hicn-light/src/hicn/test/test-pool.cc @@ -0,0 +1,196 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/pool.h> +} + +/* + * TODO + * - test max_size + */ + +#define DEFAULT_SIZE 10 + +class PoolTest : public ::testing::Test { + protected: + PoolTest() {} + virtual ~PoolTest() {} + + int *pool; +}; + +TEST_F(PoolTest, PoolAllocation) { + int rc; + + pool_init(pool, DEFAULT_SIZE, 0); + + size_t pool_size = next_pow2(DEFAULT_SIZE); + + EXPECT_EQ(pool_get_alloc_size(pool), pool_size); + + /* Check that free indices and bitmaps are correctly initialize */ + off_t *fi = pool_get_free_indices(pool); + EXPECT_EQ(vector_len(fi), pool_size); + EXPECT_EQ(fi[0], (long)(pool_size - 1)); + EXPECT_EQ(fi[pool_size - 1], 0); + + /* The allocated size of the underlying vector should be the next power of two + */ + EXPECT_EQ(vector_get_alloc_size(fi), pool_size); + + bitmap_t *fb = pool_get_free_bitmap(pool); + EXPECT_TRUE(bitmap_is_set(fb, 0)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size - 2)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size - 1)); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size)); + + /* Getting elements from the pool should correctly update the free indices + * and bitmap */ + int *elt; + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), pool_size - 1); + EXPECT_TRUE(bitmap_is_unset(fb, 0)); + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), pool_size - 2); + EXPECT_TRUE(bitmap_is_unset(fb, 1)); + + for (unsigned i = 0; i < pool_size - 4; i++) { + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + } + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), 1UL); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 2)); + + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + EXPECT_EQ(vector_len(fi), 0UL); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 1)); + + /* + * Getting elements within the allocated range should not have triggered a + * resize + */ + EXPECT_EQ(pool_len(pool), pool_size); + + /* + * Getting elements once the allocated range has been exceeded should + * trigger a resize + */ + rc = pool_get(pool, elt); + EXPECT_GE(rc, 0); + + EXPECT_EQ(pool_get_alloc_size(pool), pool_size * 2); + + EXPECT_EQ(pool_len(pool), pool_size + 1); + + /* + * Doubling the size, we should have again pool_size elements free, minus 1 + */ + EXPECT_EQ(pool_get_free_indices_size(pool), pool_size - 1); + + /* + * NOTE: this is wrong as there has been a realloc and the old fi + * pointer is now invalid + */ + // EXPECT_EQ(vector_len(fi), pool_size - 1); + + /* And the bitmap should also be correctly modified */ + fb = pool_get_free_bitmap(pool); + EXPECT_TRUE(bitmap_is_unset(fb, pool_size)); + + /* Check that surrounding values are also correct */ + EXPECT_TRUE(bitmap_is_unset(fb, pool_size - 1)); + EXPECT_TRUE(bitmap_is_set(fb, pool_size + 1)); + + /* Setting elements after should through */ + + /* Check that free indices and bitmaps are correctly updated */ + + pool_free(pool); +} + +TEST_F(PoolTest, PoolPut) { + pool_init(pool, DEFAULT_SIZE, 0); + + int *elt; + pool_get(pool, elt); + *elt = 10; + pool_put(pool, elt); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetForceBitmapRealloc) { + const int N = 64; + int *elts[N]; + int *elt = NULL; + pool_init(pool, N, 0); + + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + pool_get(pool, elt); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetAfterReleasing) { + int *elt1 = NULL, *elt2 = NULL, *tmp = NULL; + pool_init(pool, DEFAULT_SIZE, 0); + + // If two elements are requested... + off_t id1 = pool_get(pool, elt1); + pool_get(pool, tmp); + + // ...and the first one is released... + pool_put(pool, elt1); + + // ...requesting a new one should return + // the first one (that was freed) + off_t id2 = pool_get(pool, elt2); + EXPECT_EQ(id1, id2); + EXPECT_EQ(elt1, elt2); + + pool_free(pool); +} + +TEST_F(PoolTest, PoolGetMultipleElementsAfterReleasing) { + const int N = 2; + int *elts[N]; + pool_init(pool, N, 0); + + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + for (int i = 0; i < N; i++) pool_put(pool, elts[i]); + for (int i = 0; i < N; i++) pool_get(pool, elts[i]); + + pool_free(pool); +} diff --git a/hicn-light/src/hicn/test/test-probe_generator.cc b/hicn-light/src/hicn/test/test-probe_generator.cc new file mode 100644 index 000000000..4d6cfa8f7 --- /dev/null +++ b/hicn-light/src/hicn/test/test-probe_generator.cc @@ -0,0 +1,154 @@ +/* + * 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 <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <arpa/inet.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/strategies/probe_generator.h> +} + +class ProbeGeneratorTest : public ::testing::Test { + protected: + ProbeGeneratorTest() {} + + virtual ~ProbeGeneratorTest() {} +}; + +TEST_F(ProbeGeneratorTest, ProbeGeneratorRegisterProbe) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorTime) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + Ticks t1 = register_probe(pg, 1); + Ticks t2 = get_probe_send_time(pg, 1); + + EXPECT_TRUE(t2 != 0); + EXPECT_TRUE(t1 == t2); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorDeleteProbe) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + delete_probe(pg, 1); + delete_probe(pg, 3); + + t = get_probe_send_time(pg, 1); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} + +TEST_F(ProbeGeneratorTest, ProbeGeneratorDeleteAll) { + probe_generator_t *pg = create_probe_generator(); + EXPECT_FALSE(pg == nullptr); + + register_probe(pg, 1); + register_probe(pg, 2); + register_probe(pg, 3); + register_probe(pg, 4); + + Ticks t = get_probe_send_time(pg, 1); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_TRUE(t != 0); + + t = get_probe_send_time(pg, 5); + EXPECT_FALSE(t != 0); + + delete_all_probes(pg); + + t = get_probe_send_time(pg, 1); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 2); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 3); + EXPECT_FALSE(t != 0); + + t = get_probe_send_time(pg, 4); + EXPECT_FALSE(t != 0); + + destroy_probe_generator(pg); +} diff --git a/hicn-light/src/hicn/test/test-ring.cc b/hicn-light/src/hicn/test/test-ring.cc new file mode 100644 index 000000000..51f1f5327 --- /dev/null +++ b/hicn-light/src/hicn/test/test-ring.cc @@ -0,0 +1,99 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/ring.h> +} + +#define DEFAULT_SIZE 10UL + +class RingTest : public ::testing::Test { + protected: + RingTest() { ring_init(ring, DEFAULT_SIZE); } + virtual ~RingTest() { ring_free(ring); } + + int *ring = NULL; +}; + +/* TEST: Ring allocation and initialization */ +TEST_F(RingTest, RingAddOne) { + int val = -1; + /* Allocated size should be the next power of two */ + EXPECT_EQ(ring_get_size(ring), 0UL); + ring_add_value(ring, 1); + EXPECT_EQ(ring_get_size(ring), 1UL); + ring_get(ring, 0, &val); + EXPECT_EQ(val, 1); + EXPECT_EQ(ring_get_size(ring), 1UL); + ring_advance(ring, 1); + EXPECT_EQ(ring_get_size(ring), 0UL); +} + +TEST_F(RingTest, RingAddMany) { + size_t i = 0; + int val = -1; + size_t count = 0; + + /* Allocated size should be the next power of two */ + EXPECT_EQ(ring_get_size(ring), 0UL); + for (unsigned i = 0; i < DEFAULT_SIZE; i++) ring_add_value(ring, i); + EXPECT_EQ(ring_get_size(ring), DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, 1, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, 1UL); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE + 1, { + EXPECT_EQ(val, (int)(i)); + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + // Drop one + ring_add_value(ring, DEFAULT_SIZE); + EXPECT_EQ(ring_get_size(ring), DEFAULT_SIZE); + + count = 0; + ring_enumerate_n(ring, i, &val, DEFAULT_SIZE, { + EXPECT_EQ(val, (int)(i + 1)); // all values shoud be shifted + count++; + }); + EXPECT_EQ(count, DEFAULT_SIZE); + + ring_advance(ring, DEFAULT_SIZE); + EXPECT_EQ(ring_get_size(ring), 0UL); +} diff --git a/hicn-light/src/hicn/test/test-strategy-best-path.cc b/hicn-light/src/hicn/test/test-strategy-best-path.cc new file mode 100644 index 000000000..327c47144 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-best-path.cc @@ -0,0 +1,107 @@ +/* + * 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 <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/best_path.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID1 NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyBestpathTest : public ::testing::Test { + protected: + StrategyBestpathTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_BESTPATH, + .options = + { + .bestpath = {}, + }, + .state = {.bestpath = {}}, + }; + + strategy_initialize(&entry, nullptr); + + // test init + EXPECT_EQ(entry.forwarder, nullptr); + EXPECT_EQ(entry.state.bestpath.best_nexthop, (unsigned)~0); + EXPECT_EQ(entry.state.bestpath.probing_state, PROBING_OFF); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + + virtual ~StrategyBestpathTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t *msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyBestpathTest, emptyNexthop) { + nexthops_t *nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)0); +} + +TEST_F(StrategyBestpathTest, faceExists) { + nexthops_t *nexthops; + + nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + entry.state.bestpath.probing_state = PROBING_OFF; + entry.state.bestpath.best_nexthop = NEXTHOP_ID2; + + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(nexthops, NEXTHOP_ID1)); + + EXPECT_TRUE(entry.state.bestpath.probing_state == PROBING_OFF); + EXPECT_EQ(entry.state.bestpath.best_nexthop, NEXTHOP_ID2); +} diff --git a/hicn-light/src/hicn/test/test-strategy-load-balancing.cc b/hicn-light/src/hicn/test/test-strategy-load-balancing.cc new file mode 100644 index 000000000..edac5669f --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-load-balancing.cc @@ -0,0 +1,152 @@ +/* + * 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 <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyLoadBalancing : public ::testing::Test { + protected: + StrategyLoadBalancing() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_LOADBALANCER, + .options = + { + .random = {}, + }, + .state = {.random = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + virtual ~StrategyLoadBalancing() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyLoadBalancing, SingleNexthop) { + /* Add a single nexthop */ + off_t id; + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyLoadBalancing, MultipleNexthops) { + off_t id, id2; + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + id2 = nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + strategy_add_nexthop(&entry, &available_nexthops_, id2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE((nexthops_contains(nexthops, NEXTHOP_ID)) || + (nexthops_contains(nexthops, NEXTHOP_ID2))); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_TRUE((nexthop == NEXTHOP_ID) || (nexthop == NEXTHOP_ID2)); + } +} diff --git a/hicn-light/src/hicn/test/test-strategy-random.cc b/hicn-light/src/hicn/test/test-strategy-random.cc new file mode 100644 index 000000000..bd9b70120 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-random.cc @@ -0,0 +1,150 @@ +/* + * 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 <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/core/strategy_vft.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID NEXTHOP(28) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyRandomTest : public ::testing::Test { + protected: + StrategyRandomTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_RANDOM, + .options = + { + .random = {}, + }, + .state = {.random = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + virtual ~StrategyRandomTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyRandomTest, SingleNexthop) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyRandomTest, MultipleNexthops) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID); + } +} diff --git a/hicn-light/src/hicn/test/test-strategy-replication.cc b/hicn-light/src/hicn/test/test-strategy-replication.cc new file mode 100644 index 000000000..ab7dae1f7 --- /dev/null +++ b/hicn-light/src/hicn/test/test-strategy-replication.cc @@ -0,0 +1,163 @@ +/* + * 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 <gmock/gmock.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/core/strategy.h> +#include <hicn/strategies/random.h> +} + +#define MAX_TESTS 10 + +#define NEXTHOP_ID1 NEXTHOP(28) +#define NEXTHOP_ID2 NEXTHOP(29) +#define UNKNOWN_ID1 NEXTHOP(0) +#define UNKNOWN_ID2 NEXTHOP(1) + +class StrategyReplicationTest : public ::testing::Test { + protected: + StrategyReplicationTest() { + /* Strategy and strategy entry */ + entry = { + .type = STRATEGY_TYPE_REPLICATION, + .options = + { + .replication = {}, + }, + .state = {.replication = {}}, + }; + + strategy_initialize(&entry, nullptr); + + /* Available nexthops */ + available_nexthops_ = NEXTHOPS_EMPTY; + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)0); + + /* Message buffer */ + msgbuf_ = NULL; + ticks_ = ticks_now(); + } + + virtual ~StrategyReplicationTest() {} + + strategy_entry_t entry; + nexthops_t available_nexthops_; + msgbuf_t* msgbuf_; + Ticks ticks_; +}; + +TEST_F(StrategyReplicationTest, SingleNexthop) { + off_t id; + + /* Add a single nexthop */ + id = nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)1); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + for (unsigned i = 0; i < MAX_TESTS; i++) { + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, NEXTHOP_ID1); + } + + /* Disable (move to nexthop unit tests) */ + nexthops_disable(nexthops, 0); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)0); + + nexthop = nexthops_get_one(nexthops); + EXPECT_EQ(nexthop, INVALID_NEXTHOP); +} + +TEST_F(StrategyReplicationTest, MultipleNexthops) { + off_t id; + + id = nexthops_add(&available_nexthops_, NEXTHOP_ID1); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)1); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)1); + + id = nexthops_add(&available_nexthops_, NEXTHOP_ID2); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + strategy_add_nexthop(&entry, &available_nexthops_, id); + EXPECT_EQ(nexthops_get_len(&available_nexthops_), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(&available_nexthops_), (size_t)2); + + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID1)); + EXPECT_TRUE(nexthops_contains(&available_nexthops_, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(&available_nexthops_, UNKNOWN_ID2)); + + /* Lookup */ + nexthops_t* nexthops; + nexthops = strategy_lookup_nexthops(&entry, &available_nexthops_, msgbuf_); + + EXPECT_EQ(nexthops_get_len(nexthops), (size_t)2); + EXPECT_EQ(nexthops_get_curlen(nexthops), (size_t)2); + + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID1)); + EXPECT_TRUE(nexthops_contains(nexthops, NEXTHOP_ID2)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID1)); + EXPECT_FALSE(nexthops_contains(nexthops, UNKNOWN_ID2)); + + /* Retrieve candidate */ + + unsigned nexthop; + unsigned tests = 0; + nexthops_foreach(nexthops, nexthop, { + EXPECT_TRUE(nexthop == NEXTHOP_ID1 || nexthop == NEXTHOP_ID2); + tests++; + }); + + EXPECT_EQ(tests, (unsigned)2); +} diff --git a/hicn-light/src/hicn/test/test-subscription.cc b/hicn-light/src/hicn/test/test-subscription.cc new file mode 100644 index 000000000..18ef60c0d --- /dev/null +++ b/hicn-light/src/hicn/test/test-subscription.cc @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + */ + +#include <gtest/gtest.h> + +extern "C" { +#include <hicn/core/subscription.h> +#include <hicn/base/vector.h> +} + +static inline unsigned CONN_ID = 1; +static inline unsigned CONN_ID_2 = 2; + +class SubscriptionTest : public ::testing::Test { + protected: + SubscriptionTest() { subscriptions = subscription_table_create(); } + virtual ~SubscriptionTest() { subscription_table_free(subscriptions); } + + subscription_table_t *subscriptions; +}; + +TEST_F(SubscriptionTest, CreateSubscriptionTable) { + // Check subscription table allocation + ASSERT_NE(subscriptions, nullptr); +} + +TEST_F(SubscriptionTest, SetTopic) { + hc_topics_t topics = TOPIC_STRATEGY; + + // Check that only the topic desired has been subscribed to + for (int topic = TOPIC_UNDEFINED; topic < TOPIC_N; topic <<= 1) { + if (topic == TOPIC_STRATEGY) { + EXPECT_TRUE(topics_contains(topics, (hc_topic_t)topic)); + continue; + } + EXPECT_FALSE(topics_contains(topics, (hc_topic_t)topic)); + } +} + +TEST_F(SubscriptionTest, GetObjectFromTopic) { + hc_object_type_t object_type = object_from_topic(TOPIC_STRATEGY); + EXPECT_EQ(object_type, OBJECT_STRATEGY); + + object_type = object_from_topic(TOPIC_FACE); + EXPECT_EQ(object_type, OBJECT_FACE); +} + +TEST_F(SubscriptionTest, AddSubscription) { + hc_topics_t topics = TOPIC_STRATEGY; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, AddAndRemoveSubscriptionForAllTopics) { + hc_topics_t topics = ALL_TOPICS; + int ret = subscription_table_add_topics_for_connection(subscriptions, + ALL_TOPICS, CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(num_subscriptions_removed, NUM_TOPICS); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, 0u); +} + +// Failure while adding subscription cannot be tested since it depends on vector +// reallocation + +TEST_F(SubscriptionTest, AddSubscriptionAlreadyAdded) { + hc_topics_t topics = TOPIC_STRATEGY; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Subscribe again to same topic + ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, -2); // -2 = already-added subscription + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, GetSubscriptionsForConnectionWithoutSubscriptions) { + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, (hc_topics_t)0); +} + +TEST_F(SubscriptionTest, GetSubscriptionsForConnectionWithMultipleSubs) { + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); + + // Add another subscription + ret = subscription_table_add_topics_for_connection(subscriptions, TOPIC_PROBE, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics |= TOPIC_PROBE); +} + +TEST_F(SubscriptionTest, RemoveSubscription) { + // Add subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove one of the previously added subscriptions + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, + TOPIC_STRATEGY, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 1); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, TOPIC_FACE); +} + +TEST_F(SubscriptionTest, RemoveMultipleSubscriptions) { + // Add subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE | TOPIC_PROBE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove two of the previously added subscriptions + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection( + subscriptions, TOPIC_STRATEGY | TOPIC_FACE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 2); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, TOPIC_PROBE); +} + +TEST_F(SubscriptionTest, RemoveNonRegistredSubscription) { + // Remove a subscription that is not present + int num_subscriptions_removed = + subscription_table_remove_topics_for_connection(subscriptions, + TOPIC_PROBE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 0); + + // Add two new subscriptions + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + // Remove subscription that was not registred previously + num_subscriptions_removed = subscription_table_remove_topics_for_connection( + subscriptions, TOPIC_PROBE, CONN_ID); + EXPECT_EQ(num_subscriptions_removed, 0); + + hc_topics_t topics_ret = + subscription_table_get_topics_for_connection(subscriptions, CONN_ID); + EXPECT_EQ(topics_ret, topics); +} + +TEST_F(SubscriptionTest, GetConnectionsForSubscription) { + // Add subscriptions for two connections + hc_topics_t topics = TOPIC_STRATEGY | TOPIC_FACE; + int ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID); + EXPECT_EQ(ret, 0); // 0 = success + + topics = TOPIC_STRATEGY; + ret = subscription_table_add_topics_for_connection(subscriptions, topics, + CONN_ID_2); + EXPECT_EQ(ret, 0); // 0 = success + + // Check the connections associated with the strategy topic + unsigned *conn_ids = subscription_table_get_connections_for_topic( + subscriptions, TOPIC_STRATEGY); + EXPECT_EQ(vector_len(conn_ids), 2u); + EXPECT_TRUE(conn_ids[0] == CONN_ID || conn_ids[0] == CONN_ID_2); + EXPECT_TRUE(conn_ids[1] == CONN_ID || conn_ids[1] == CONN_ID_2); + + // Check the connections associated with the face topic + conn_ids = + subscription_table_get_connections_for_topic(subscriptions, TOPIC_FACE); + EXPECT_EQ(vector_len(conn_ids), 1u); + EXPECT_EQ(conn_ids[0], (unsigned)CONN_ID); +}
\ No newline at end of file diff --git a/hicn-light/src/hicn/test/test-vector.cc b/hicn-light/src/hicn/test/test-vector.cc new file mode 100644 index 000000000..fb30a8228 --- /dev/null +++ b/hicn-light/src/hicn/test/test-vector.cc @@ -0,0 +1,148 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> +#include <netinet/in.h> + +extern "C" { +#define WITH_TESTS +#include <hicn/base/vector.h> +} + +/* + * TODO + * - test max_size + */ + +#define DEFAULT_SIZE 10 +const size_t N_ELEMENTS = 5; + +class VectorTest : public ::testing::Test { + protected: + VectorTest() { vector_init(vector, DEFAULT_SIZE, 0); } + virtual ~VectorTest() { vector_free(vector); } + + int *vector = NULL; +}; + +/* TEST: Vector allocation and initialization */ +TEST_F(VectorTest, VectorAllocate) { + /* Allocated size should be the next power of two */ + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); + + /* Setting elements within the allocated size should not trigger a resize */ + vector_ensure_pos(vector, 15); + EXPECT_EQ(vector_get_alloc_size(vector), 16UL); + + /* Setting elements after should through */ + vector_ensure_pos(vector, 16); + EXPECT_EQ(vector_get_alloc_size(vector), 32UL); + + /* Check that free indices and bitmaps are correctly updated */ +} + +TEST_F(VectorTest, VectorSize) { + vector_push(vector, 109); + int size = vector_len(vector); + EXPECT_EQ(size, 1); + vector_push(vector, 109); + size = vector_len(vector); + EXPECT_EQ(size, 2); + vector_push(vector, 109); + size = vector_len(vector); + EXPECT_EQ(size, 3); +} + +TEST_F(VectorTest, VectorCheckValue) { + vector_push(vector, 109); + vector_push(vector, 200); + EXPECT_EQ(vector[0], 109); + EXPECT_EQ(vector[1], 200); +} + +TEST_F(VectorTest, VectorEnsurePos) { + printf(" %p\n", vector); + vector_ensure_pos(vector, 1025); + for (int i = 0; i < 1025; i++) { + // printf("i %d\n", i); + // printf (" %p\n", vector); + vector_push(vector, i); + } + int size = vector_len(vector); + EXPECT_EQ(size, 1025); +} + +TEST_F(VectorTest, RemoveElement) { + // Populate vector + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + EXPECT_EQ(vector_len(vector), N_ELEMENTS); + for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); + + // Remove element + int value_to_remove = 3; + int num_removed = vector_remove_unordered(vector, value_to_remove); + + EXPECT_EQ(vector_len(vector), N_ELEMENTS - 1); + EXPECT_EQ(num_removed, 1); + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_NE(vector[i], value_to_remove); +} + +TEST_F(VectorTest, RemoveDuplicatedElement) { + // Populate vector + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + EXPECT_EQ(vector_len(vector), N_ELEMENTS); + for (size_t i = 0; i < vector_len(vector); i++) EXPECT_EQ(vector[i], (int)i); + vector[0] = 3; // Duplicate element + + // Remove (duplicated) elements + int value_to_remove = 3; + int num_removed = vector_remove_unordered(vector, value_to_remove); + + EXPECT_EQ(vector_len(vector), N_ELEMENTS - 2); + EXPECT_EQ(num_removed, 2); + for (size_t i = 0; i < vector_len(vector); i++) + EXPECT_NE(vector[i], value_to_remove); +} + +TEST_F(VectorTest, Iterate) { + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(vector, i); + + int count = 0; + int *elem; + vector_foreach(vector, elem, { EXPECT_EQ(*elem, count++); }); +} + +TEST_F(VectorTest, MultipleResize) { + // Use small vector (size=1) to force multiple realloc operations + int *small_vector; + vector_init(small_vector, 1, 0); + + for (size_t i = 0; i < N_ELEMENTS; i++) vector_push(small_vector, i); + + for (size_t i = 0; i < N_ELEMENTS; i++) EXPECT_EQ(small_vector[i], (int)i); + + EXPECT_EQ(vector_len(small_vector), 5UL); + EXPECT_EQ(vector_get_alloc_size(small_vector), 8UL); + + vector_free(small_vector); +}
\ No newline at end of file |