aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/test')
-rw-r--r--libtransport/src/test/CMakeLists.txt54
-rw-r--r--libtransport/src/test/main.cc1
-rw-r--r--libtransport/src/test/test_aggregated_header.cc622
-rw-r--r--libtransport/src/test/test_auth.cc178
-rw-r--r--libtransport/src/test/test_consumer_producer_rtc.cc7
-rw-r--r--libtransport/src/test/test_core_manifest.cc110
-rw-r--r--libtransport/src/test/test_event_thread.cc36
-rw-r--r--libtransport/src/test/test_fec_base_rely.cc453
-rw-r--r--libtransport/src/test/test_fec_base_rs.cc412
-rw-r--r--libtransport/src/test/test_fec_reedsolomon.cc122
-rw-r--r--libtransport/src/test/test_fec_rely_wrapper.cc131
-rw-r--r--libtransport/src/test/test_fixed_block_allocator.cc211
-rw-r--r--libtransport/src/test/test_interest.cc20
-rw-r--r--libtransport/src/test/test_memif_connector.cc152
-rw-r--r--libtransport/src/test/test_packet.cc11
-rw-r--r--libtransport/src/test/test_packet_allocator.cc106
-rw-r--r--libtransport/src/test/test_quality_score.cc135
-rw-r--r--libtransport/src/test/test_sessions.cc77
-rw-r--r--libtransport/src/test/test_thread_pool.cc70
19 files changed, 2673 insertions, 235 deletions
diff --git a/libtransport/src/test/CMakeLists.txt b/libtransport/src/test/CMakeLists.txt
index 26fe7aee1..e7018ceed 100644
--- a/libtransport/src/test/CMakeLists.txt
+++ b/libtransport/src/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
+# Copyright (c) 2021-2022 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
@@ -11,42 +11,68 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-include(BuildMacros)
-
+##############################################################
+# Test sources
+##############################################################
list(APPEND TESTS_SRC
main.cc
+ test_aggregated_header.cc
test_auth.cc
- test_consumer_producer_rtc.cc
+ # test_consumer_producer_rtc.cc
test_core_manifest.cc
- test_event_thread.cc
+ # test_event_thread.cc
+ test_fec_base_rs.cc
test_fec_reedsolomon.cc
+ test_fixed_block_allocator.cc
test_indexer.cc
test_interest.cc
test_packet.cc
+ test_packet_allocator.cc
+ test_quality_score.cc
+ test_sessions.cc
+ test_thread_pool.cc
)
if (ENABLE_RELY)
list(APPEND TESTS_SRC
test_fec_rely_wrapper.cc
+ test_fec_base_rely.cc
+ )
+endif()
+
+if (UNIX AND NOT APPLE)
+ list(APPEND TESTS_SRC
+ test_memif_connector.cc
)
endif()
-build_executable(unit_tests
+
+##############################################################
+# Link libraries
+##############################################################
+set(MEMIF_MODULE_LIBRARIES
+ ${LIBRARIES}
+ ${LIBTRANSPORT_SHARED}
+ ${GTEST_LIBRARIES}
+)
+
+
+##############################################################
+# Build single unit test executable and add it to test list
+##############################################################
+build_executable(libtransport_tests
NO_INSTALL
SOURCES ${TESTS_SRC}
LINK_LIBRARIES
- ${LIBRARIES}
- ${LIBTRANSPORT_STATIC}
- ${GTEST_LIBRARIES}
+ ${MEMIF_MODULE_LIBRARIES}
INCLUDE_DIRS
- ${LIBTRANSPORT_INCLUDE_DIRS}
- ${LIBHICN_INCLUDE_DIRS}
- ${LIBTRANSPORT_INTERNAL_INCLUDE_DIRS}
+ $<TARGET_PROPERTY:${LIBTRANSPORT_SHARED},INCLUDE_DIRECTORIES>
${GTEST_INCLUDE_DIRS}
DEPENDS gtest ${LIBTRANSPORT_SHARED}
COMPONENT ${LIBTRANSPORT_COMPONENT}
- DEFINITIONS "${COMPILER_DEFINITIONS}"
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
LINK_FLAGS ${LINK_FLAGS}
)
-add_test_internal(unit_tests)
+add_test_internal(libtransport_tests)
diff --git a/libtransport/src/test/main.cc b/libtransport/src/test/main.cc
index a4d7ce1b3..591ed0d5b 100644
--- a/libtransport/src/test/main.cc
+++ b/libtransport/src/test/main.cc
@@ -16,7 +16,6 @@
#include <gtest/gtest.h>
int main(int argc, char **argv) {
- srand(time(0));
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} \ No newline at end of file
diff --git a/libtransport/src/test/test_aggregated_header.cc b/libtransport/src/test/test_aggregated_header.cc
new file mode 100644
index 000000000..0d88af5ab
--- /dev/null
+++ b/libtransport/src/test/test_aggregated_header.cc
@@ -0,0 +1,622 @@
+/*
+ * 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 <hicn/transport/errors/not_implemented_exception.h>
+#include <protocols/rtc/rtc_packet.h>
+#include <test/packet_samples.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+// The fixture for testing class Foo.
+class AggregatedPktHeaderTest : public ::testing::Test {
+ protected:
+ AggregatedPktHeaderTest() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~AggregatedPktHeaderTest() {
+ // 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).
+ }
+};
+
+} // namespace
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit) {
+ uint8_t buf[1500];
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // print
+ // for (uint16_t i = 0; i < 40; i++){
+ // std::cout << (int) i << " " << (int) buf[i] << std::endl;
+ //}
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit255) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14}; // 255
+ uint16_t pkt2_len = 255;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt2_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add2Packets8bit256) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15}; // 256
+ uint16_t pkt2_len = 256;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt2_len, 2);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add4Packets8bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
+ uint16_t pkt3_len = 10;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len) = pkt3[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len + pkt3_len) = pkt4[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Add4Packets16bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 260
+ uint16_t pkt3_len = 260;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt3_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+ uint8_t* ptr = hdr.getPayloadAppendPtr();
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ *(ptr + i) = pkt1[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ *(ptr + i + pkt1_len) = pkt2[i];
+ }
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len) = pkt3[i];
+ }
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ *(ptr + i + pkt1_len + pkt2_len + pkt3_len) = pkt4[i];
+ }
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ hdr.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Defrag4Packets8bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
+ uint16_t pkt3_len = 10;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt1_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+
+ uint16_t offset = protocol::rtc::DATA_HEADER_SIZE + 8; // 8 = aggr hdr
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ buf[i + offset] = pkt1[i];
+ }
+ offset += pkt1_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ buf[i + offset] = pkt2[i];
+ }
+ offset += pkt2_len;
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ buf[i + offset] = pkt3[i];
+ }
+ offset += pkt3_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ buf[i + offset] = pkt4[i];
+ }
+
+ protocol::rtc::AggrPktHeader hdr2(buf + protocol::rtc::DATA_HEADER_SIZE);
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ uint8_t packet_number = hdr2.getNumberOfPackets();
+ EXPECT_EQ(packet_number, 4);
+
+ hdr2.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr2.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr2.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr2.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+TEST_F(AggregatedPktHeaderTest, Defrag4Packets16bit) {
+ uint8_t buf[1500];
+
+ std::vector<uint8_t> pkt1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+ uint16_t pkt1_len = 14;
+
+ std::vector<uint8_t> pkt2 = {11, 12, 13, 14, 15, 16, 17};
+ uint16_t pkt2_len = 7;
+
+ std::vector<uint8_t> pkt3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 20
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 60
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 80
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 100
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 120
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 140
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 160
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 180
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 200
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 220
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, // 240
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 260
+ uint16_t pkt3_len = 260;
+
+ std::vector<uint8_t> pkt4 = {100, 110};
+ uint16_t pkt4_len = 2;
+
+ for (uint16_t i = 0; i < 1500; i++) {
+ buf[i] = 0;
+ }
+
+ // skip protocol::rtc::DATA_HEADER_SIZE that will be the rtc header
+ protocol::rtc::AggrPktHeader hdr(buf + protocol::rtc::DATA_HEADER_SIZE,
+ pkt3_len, 4);
+ hdr.addPacketToHeader(0, pkt1_len);
+ hdr.addPacketToHeader(1, pkt2_len);
+ hdr.addPacketToHeader(2, pkt3_len);
+ hdr.addPacketToHeader(3, pkt4_len);
+
+ uint16_t offset = protocol::rtc::DATA_HEADER_SIZE + 12; // 12 = aggr hdr
+
+ // copy packet 1
+ for (uint16_t i = 0; i < pkt1_len; i++) {
+ buf[i + offset] = pkt1[i];
+ }
+ offset += pkt1_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt2_len; i++) {
+ buf[i + offset] = pkt2[i];
+ }
+ offset += pkt2_len;
+
+ // copy packet 3
+ for (uint16_t i = 0; i < pkt3_len; i++) {
+ buf[i + offset] = pkt3[i];
+ }
+ offset += pkt3_len;
+
+ // copy packet 2
+ for (uint16_t i = 0; i < pkt4_len; i++) {
+ buf[i + offset] = pkt4[i];
+ }
+
+ protocol::rtc::AggrPktHeader hdr2(buf + protocol::rtc::DATA_HEADER_SIZE);
+
+ uint8_t* pkt_ptr = nullptr;
+ uint16_t pkt_len = 0;
+
+ uint8_t packet_number = hdr2.getNumberOfPackets();
+ EXPECT_EQ(packet_number, 4);
+
+ hdr2.getPointerToPacket(0, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt1_len);
+ for (uint16_t i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt1[i]);
+ }
+
+ hdr2.getPointerToPacket(1, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt2_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt2[i]);
+ }
+
+ hdr2.getPointerToPacket(2, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt3_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt3[i]);
+ }
+
+ hdr2.getPointerToPacket(3, &pkt_ptr, &pkt_len);
+ EXPECT_EQ(pkt_len, pkt4_len);
+ for (int i = 0; i < pkt_len; i++) {
+ EXPECT_EQ(*(pkt_ptr + i), pkt4[i]);
+ }
+}
+
+} // namespace core
+} // namespace transport
diff --git a/libtransport/src/test/test_auth.cc b/libtransport/src/test/test_auth.cc
index db1c3b52f..d7fd55433 100644
--- a/libtransport/src/test/test_auth.cc
+++ b/libtransport/src/test/test_auth.cc
@@ -15,10 +15,15 @@
#include <gtest/gtest.h>
#include <hicn/transport/auth/crypto_hash.h>
-#include <hicn/transport/auth/identity.h>
#include <hicn/transport/auth/signer.h>
#include <hicn/transport/auth/verifier.h>
#include <hicn/transport/core/content_object.h>
+#include <openssl/rand.h>
+
+using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
+using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
+using EC_KEY_ptr = std::unique_ptr<EC_KEY, decltype(&::EC_KEY_free)>;
+using DSA_ptr = std::unique_ptr<DSA, decltype(&::DSA_free)>;
namespace transport {
namespace auth {
@@ -50,11 +55,23 @@ TEST_F(AuthTest, VoidVerifier) {
}
TEST_F(AuthTest, AsymmetricRSA) {
- // Create the RSA signer from an Identity object
- Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
- 30, "RSAVerifier");
-
- std::shared_ptr<Signer> signer = identity.getSigner();
+ // Create the RSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ RSA_ptr rsa(RSA_new(), ::RSA_free);
+ BN_ptr pub_exp(BN_new(), ::BN_free);
+
+ BN_set_word(pub_exp.get(), RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa.get(), 2048u, pub_exp.get(), NULL))
+ throw errors::RuntimeException("can't generate the key");
+ RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
+ RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);
+ if (1 != EVP_PKEY_set1_RSA(pubKey.get(), rsa_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::RSA_SHA256, privateKey, pubKey);
// Create a content object
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
@@ -68,61 +85,112 @@ TEST_F(AuthTest, AsymmetricRSA) {
// Create the RSA verifier
std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+ std::make_shared<AsymmetricVerifier>(pubKey);
EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
EXPECT_EQ(signer->getSuite(), CryptoSuite::RSA_SHA256);
- EXPECT_EQ(signer->getSignatureSize(), 128u);
+ EXPECT_EQ(signer->getSignatureSize(), 256u);
EXPECT_EQ(verifier->verifyPackets(&packet), VerificationPolicy::ACCEPT);
}
TEST_F(AuthTest, AsymmetricBufferRSA) {
- // Create the RSA signer from an Identity object
- Identity identity("test_rsa.p12", PASSPHRASE, CryptoSuite::RSA_SHA256, 1024u,
- 30, "RSAVerifier");
+ // Create the RSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ RSA_ptr rsa(RSA_new(), ::RSA_free);
+ BN_ptr pub_exp(BN_new(), ::BN_free);
+
+ BN_set_word(pub_exp.get(), RSA_F4);
+ if (1 != RSA_generate_key_ex(rsa.get(), 2048u, pub_exp.get(), NULL))
+ throw errors::RuntimeException("can't generate the key");
+ RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
+ RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);
+ if (1 != EVP_PKEY_set1_RSA(pubKey.get(), rsa_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_RSA(privateKey.get(), rsa_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::RSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
}
TEST_F(AuthTest, AsymmetricBufferDSA) {
- // Create the DSA signer from an Identity object
- Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
- 30, "DSAVerifier");
+ // Create the DSA keys
+
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+
+ DSA_ptr dsa(DSA_new(), ::DSA_free);
+ unsigned char buf[32];
+ if (RAND_bytes(buf, sizeof(buf)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa.get(), 1024u, buf, sizeof(buf), NULL, NULL,
+ NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<X509> cert(X509_new(), ::X509_free);
+ X509_set_pubkey(cert.get(), privateKey.get());
+ std::shared_ptr<EVP_PKEY> pubKey(X509_get_pubkey(cert.get()), EVP_PKEY_free);
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::DSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
}
TEST_F(AuthTest, AsymmetricVerifierDSA) {
- // Create the DSA signer from an Identity object
- Identity identity("test_dsa.p12", PASSPHRASE, CryptoSuite::DSA_SHA256, 1024u,
- 30, "DSAVerifier");
+ // Create the DSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
- std::shared_ptr<Signer> signer = identity.getSigner();
+ DSA_ptr dsa(DSA_new(), ::DSA_free);
+ unsigned char buf[32];
+ if (RAND_bytes(buf, sizeof(buf)) != 1) {
+ throw errors::RuntimeException("can't generate the key");
+ }
+ if (DSA_generate_parameters_ex(dsa.get(), 1024u, buf, sizeof(buf), NULL, NULL,
+ NULL) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (DSA_generate_key(dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()) != 1)
+ throw errors::RuntimeException("can't generate the key");
+ if (1 != EVP_PKEY_set1_DSA(privateKey.get(), dsa.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<X509> cert(X509_new(), ::X509_free);
+ X509_set_pubkey(cert.get(), privateKey.get());
+ std::shared_ptr<EVP_PKEY> pubKey(X509_get_pubkey(cert.get()), EVP_PKEY_free);
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::DSA_SHA256, privateKey, pubKey);
// Create a content object
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
@@ -134,7 +202,7 @@ TEST_F(AuthTest, AsymmetricVerifierDSA) {
// EXPECT_EQ(signer->getSignatureSize(), 256u);
signer->signPacket(&packet);
std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
+ std::make_shared<AsymmetricVerifier>(cert);
EXPECT_EQ(packet.getFormat(), HF_INET6_TCP_AH);
EXPECT_EQ(signer->getHashType(), CryptoHashType::SHA256);
@@ -143,33 +211,59 @@ TEST_F(AuthTest, AsymmetricVerifierDSA) {
}
TEST_F(AuthTest, AsymmetricBufferECDSA) {
- // Create the ECDSA signer from an Identity object
- Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
- 256u, 30, "ECDSAVerifier");
+ // Create the ECDSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ EC_KEY_ptr ec_priv(EC_KEY_new_by_curve_name(NID_secp256k1), ::EC_KEY_free);
+ EC_KEY_ptr ec_pub(EC_KEY_new(), ::EC_KEY_free);
+ EC_KEY_set_asn1_flag(ec_priv.get(), OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_priv.get()) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (1 != EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY_set_group(ec_pub.get(), EC_KEY_get0_group(ec_priv.get()));
+ EC_KEY_set_public_key(ec_pub.get(), EC_KEY_get0_public_key(ec_priv.get()));
+ if (1 != EVP_PKEY_set1_EC_KEY(pubKey.get(), ec_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::ECDSA_SHA256, privateKey, pubKey);
- std::shared_ptr<AsymmetricSigner> signer = identity.getSigner();
std::string payload = "bonjour";
std::vector<uint8_t> buffer(payload.begin(), payload.end());
signer->signBuffer(buffer);
std::vector<uint8_t> sig = signer->getSignature();
- std::shared_ptr<X509> cert = identity.getCertificate();
- AsymmetricVerifier verif(cert);
- bool res = verif.verifyBuffer(
+ std::shared_ptr<AsymmetricVerifier> verif =
+ std::make_shared<AsymmetricVerifier>(pubKey);
+ bool res = verif->verifyBuffer(
buffer, std::vector<uint8_t>(sig.data(), sig.data() + sig.size()),
CryptoHashType::SHA256);
EXPECT_EQ(res, true);
-}
+} // namespace auth
TEST_F(AuthTest, AsymmetricVerifierECDSA) {
- Identity identity("test_ecdsa.p12", PASSPHRASE, CryptoSuite::ECDSA_SHA256,
- 256u, 30, "ECDSAVerifier");
-
- std::shared_ptr<Signer> signer = identity.getSigner();
- std::shared_ptr<Verifier> verifier =
- std::make_shared<AsymmetricVerifier>(identity.getCertificate());
- // Create a content object
+ // Create the ECDSA keys
+ std::shared_ptr<EVP_PKEY> privateKey(EVP_PKEY_new(), EVP_PKEY_free);
+ std::shared_ptr<EVP_PKEY> pubKey(EVP_PKEY_new(), EVP_PKEY_free);
+ EC_KEY_ptr ec_priv(EC_KEY_new_by_curve_name(NID_secp256k1), ::EC_KEY_free);
+ EC_KEY_ptr ec_pub(EC_KEY_new(), ::EC_KEY_free);
+ EC_KEY_set_asn1_flag(ec_priv.get(), OPENSSL_EC_NAMED_CURVE);
+ if (EC_KEY_generate_key(ec_priv.get()) == 0)
+ throw errors::RuntimeException("can't generate the ecdsa key");
+ if (1 != EVP_PKEY_set1_EC_KEY(privateKey.get(), ec_priv.get()))
+ throw errors::RuntimeException("can't generate the key");
+ EC_KEY_set_group(ec_pub.get(), EC_KEY_get0_group(ec_priv.get()));
+ EC_KEY_set_public_key(ec_pub.get(), EC_KEY_get0_public_key(ec_priv.get()));
+ if (1 != EVP_PKEY_set1_EC_KEY(pubKey.get(), ec_pub.get()))
+ throw errors::RuntimeException("can't generate the key");
+
+ std::shared_ptr<AsymmetricSigner> signer = std::make_shared<AsymmetricSigner>(
+ CryptoSuite::ECDSA_SHA256, privateKey, pubKey);
+
+ std::shared_ptr<AsymmetricVerifier> verifier =
+ std::make_shared<AsymmetricVerifier>(pubKey);
for (int i = 0; i < 100; i++) {
core::ContentObject packet(HF_INET6_TCP_AH, signer->getSignatureSize());
diff --git a/libtransport/src/test/test_consumer_producer_rtc.cc b/libtransport/src/test/test_consumer_producer_rtc.cc
index 8541a9e1a..b11a6a388 100644
--- a/libtransport/src/test/test_consumer_producer_rtc.cc
+++ b/libtransport/src/test/test_consumer_producer_rtc.cc
@@ -41,7 +41,7 @@ class ConsumerProducerTest : public ::testing::Test,
rtc_timer_(io_service_),
stop_timer_(io_service_),
consumer_(TransportProtocolAlgorithms::RTC, io_service_),
- producer_(ProductionProtocolAlgorithms::RTC_PROD, io_service_),
+ producer_(ProductionProtocolAlgorithms::RTC_PROD, thread_),
producer_prefix_(prefix),
consumer_name_(name),
packets_sent_(0),
@@ -120,14 +120,13 @@ class ConsumerProducerTest : public ::testing::Test,
size_t maxBufferSize() const override { return receive_buffer_size; }
- void readError(const std::error_code ec) noexcept override {
- FAIL() << "Error while reading from RTC socket";
+ void readError(const std::error_code &ec) noexcept override {
io_service_.stop();
+ FAIL() << "Error while reading from RTC socket";
}
void readSuccess(std::size_t total_size) noexcept override {
packets_received_++;
- std::cout << "Received something" << std::endl;
}
asio::io_service io_service_;
diff --git a/libtransport/src/test/test_core_manifest.cc b/libtransport/src/test/test_core_manifest.cc
index 93f4e87cb..23fd5e342 100644
--- a/libtransport/src/test/test_core_manifest.cc
+++ b/libtransport/src/test/test_core_manifest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * 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:
@@ -17,6 +17,8 @@
#include <core/manifest_inline.h>
#include <gtest/gtest.h>
#include <hicn/transport/auth/crypto_hash.h>
+#include <hicn/transport/auth/signer.h>
+#include <hicn/transport/auth/verifier.h>
#include <test/packet_samples.h>
#include <climits>
@@ -33,7 +35,7 @@ class ManifestTest : public ::testing::Test {
protected:
using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
- ManifestTest() : name_("b001::123|321"), manifest1_(name_) {
+ ManifestTest() : name_("b001::123|321"), manifest1_(HF_INET6_TCP_AH, name_) {
// You can do set-up work for each test here.
}
@@ -97,8 +99,8 @@ TEST_F(ManifestTest, MoveConstructor) {
TEST_F(ManifestTest, SetLastManifest) {
manifest1_.clear();
- manifest1_.setFinalManifest(true);
- bool fcn = manifest1_.isFinalManifest();
+ manifest1_.setIsLast(true);
+ bool fcn = manifest1_.getIsLast();
ASSERT_TRUE(fcn == true);
}
@@ -109,13 +111,13 @@ TEST_F(ManifestTest, SetManifestType) {
ManifestType type1 = ManifestType::INLINE_MANIFEST;
ManifestType type2 = ManifestType::FLIC_MANIFEST;
- manifest1_.setManifestType(type1);
- ManifestType type_returned1 = manifest1_.getManifestType();
+ manifest1_.setType(type1);
+ ManifestType type_returned1 = manifest1_.getType();
manifest1_.clear();
- manifest1_.setManifestType(type2);
- ManifestType type_returned2 = manifest1_.getManifestType();
+ manifest1_.setType(type2);
+ ManifestType type_returned2 = manifest1_.getType();
ASSERT_EQ(type1, type_returned1);
ASSERT_EQ(type2, type_returned2);
@@ -146,17 +148,80 @@ TEST_F(ManifestTest, SetHashAlgorithm) {
ASSERT_EQ(hash3, type_returned3);
}
-TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) {
+TEST_F(ManifestTest, setParamsBytestream) {
manifest1_.clear();
- NextSegmentCalculationStrategy strategy1 =
- NextSegmentCalculationStrategy::INCREMENTAL;
+ ParamsBytestream params{
+ .final_segment = 1,
+ };
+
+ manifest1_.setParamsBytestream(params);
+ manifest1_.encode();
+
+ ContentObjectManifest manifest(manifest1_);
+ manifest.decode();
+
+ ASSERT_EQ(interface::ProductionProtocolAlgorithms::BYTE_STREAM,
+ manifest.getTransportType());
+ ASSERT_EQ(params, manifest.getParamsBytestream());
+}
+
+TEST_F(ManifestTest, SetParamsRTC) {
+ manifest1_.clear();
+
+ ParamsRTC params{
+ .timestamp = 1,
+ .prod_rate = 2,
+ .prod_seg = 3,
+ .support_fec = 1,
+ };
+
+ manifest1_.setParamsRTC(params);
+ manifest1_.encode();
- manifest1_.setNextSegmentCalculationStrategy(strategy1);
- NextSegmentCalculationStrategy type_returned1 =
- manifest1_.getNextSegmentCalculationStrategy();
+ ContentObjectManifest manifest(manifest1_);
+ manifest.decode();
+
+ ASSERT_EQ(interface::ProductionProtocolAlgorithms::RTC_PROD,
+ manifest.getTransportType());
+ ASSERT_EQ(params, manifest.getParamsRTC());
+}
- ASSERT_EQ(strategy1, type_returned1);
+TEST_F(ManifestTest, SignManifest) {
+ Name name("b001::", 0);
+ auto signer = std::make_shared<auth::SymmetricSigner>(
+ auth::CryptoSuite::HMAC_SHA256, "hunter2");
+ auto verifier = std::make_shared<auth::SymmetricVerifier>("hunter2");
+ std::shared_ptr<ContentObjectManifest> manifest;
+
+ // Instantiate Manifest
+ manifest.reset(ContentObjectManifest::createManifest(
+ HF_INET6_TCP_AH, name, ManifestVersion::VERSION_1,
+ ManifestType::INLINE_MANIFEST, false, name, signer->getHashType(),
+ signer->getSignatureFieldSize()));
+
+ // Add Manifest entry
+ auth::CryptoHash hash(signer->getHashType());
+ hash.computeDigest(std::vector<uint8_t>{0x01, 0x02, 0x03, 0x04});
+ manifest->addSuffixHash(1, hash);
+
+ // Encode manifest
+ manifest->encode();
+
+ // Sign manifest
+ signer->signPacket(manifest.get());
+
+ // Check size
+ ASSERT_EQ(manifest->payloadSize(), manifest->estimateManifestSize());
+ ASSERT_EQ(manifest->length(),
+ manifest->headerSize() + manifest->payloadSize());
+ ASSERT_EQ(ContentObjectManifest::manifestHeaderSize(
+ interface::ProductionProtocolAlgorithms::UNKNOWN),
+ manifest->manifestHeaderSize());
+
+ // Verify manifest
+ auth::VerificationPolicy policy = verifier->verifyPackets(manifest.get());
+ ASSERT_EQ(auth::VerificationPolicy::ACCEPT, policy);
}
TEST_F(ManifestTest, SetBaseName) {
@@ -198,23 +263,8 @@ TEST_F(ManifestTest, SetSuffixList) {
}
manifest1_.setBaseName(base_name);
-
core::Name ret_name = manifest1_.getBaseName();
- // auto & hash_list = manifest1_.getSuffixHashList();
-
- // bool cond;
- // int i = 0;
-
- // for (auto & item : manifest1_.getSuffixList()) {
- // auto hash = manifest1_.getHash(suffixes[i]);
- // cond = auth::CryptoHash::compareBinaryDigest(hash,
- // entries[i].second.getDigest<uint8_t>().data(),
- // entries[i].second.getType());
- // ASSERT_TRUE(cond);
- // i++;
- // }
-
ASSERT_EQ(base_name, ret_name);
delete[] entries;
diff --git a/libtransport/src/test/test_event_thread.cc b/libtransport/src/test/test_event_thread.cc
index 549ff9c1a..324250717 100644
--- a/libtransport/src/test/test_event_thread.cc
+++ b/libtransport/src/test/test_event_thread.cc
@@ -14,6 +14,7 @@
*/
#include <gtest/gtest.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <hicn/transport/utils/event_thread.h>
#include <cmath>
@@ -48,7 +49,7 @@ class EventThreadTest : public ::testing::Test {
utils::EventThread event_thread_;
};
-double average(const unsigned long samples[], int size) {
+inline double average(const unsigned long samples[], int size) {
double sum = 0;
for (int i = 0; i < size; i++) {
@@ -58,7 +59,7 @@ double average(const unsigned long samples[], int size) {
return sum / size;
}
-double stdDeviation(const unsigned long samples[], int size) {
+inline double stdDeviation(const unsigned long samples[], int size) {
double avg = average(samples, size);
double var = 0;
@@ -72,26 +73,23 @@ double stdDeviation(const unsigned long samples[], int size) {
} // namespace
TEST_F(EventThreadTest, DISABLED_SchedulingDelay) {
- using namespace std::chrono;
- const size_t size = 1000000;
- std::vector<unsigned long> samples(size);
-
- for (unsigned int i = 0; i < size; i++) {
- auto t0 = steady_clock::now();
- event_thread_.add([t0, &samples, i]() {
- auto t1 = steady_clock::now();
- samples[i] = duration_cast<nanoseconds>(t1 - t0).count();
- });
- }
+ // using namespace std::chrono;
+ // const size_t size = 1000000;
+ // std::vector<unsigned long> samples(size);
+
+ // for (unsigned int i = 0; i < size; i++) {
+ // event_thread_.add([t0, &samples, i]() {
+ // });
+ // }
- event_thread_.stop();
+ // event_thread_.stop();
- auto avg = average(&samples[0], size);
- auto sd = stdDeviation(&samples[0], size);
- (void)sd;
+ // auto avg = average(&samples[0], size);
+ // auto sd = stdDeviation(&samples[0], size);
+ // (void)sd;
- // Expect average to be less that 1 ms
- EXPECT_LT(avg, 1000000);
+ // // Expect average to be less that 1 ms
+ // EXPECT_LT(avg, 1000000);
}
} // namespace utils
diff --git a/libtransport/src/test/test_fec_base_rely.cc b/libtransport/src/test/test_fec_base_rely.cc
new file mode 100644
index 000000000..41e1eae49
--- /dev/null
+++ b/libtransport/src/test/test_fec_base_rely.cc
@@ -0,0 +1,453 @@
+/*
+ * 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 <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec_base.h>
+#include <protocols/fec_utils.h>
+#include <protocols/rtc/rtc_consts.h>
+
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <random>
+
+namespace transport {
+namespace protocol {
+
+class PacketFactory {
+ public:
+ PacketFactory(){};
+
+ ~PacketFactory(){};
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, uint32_t payload_size,
+ uint32_t payload_filler) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // create payload
+ auto buff = packet_manager.getMemBuf();
+ buff->append(payload_size);
+ std::fill(buff->writableData(), buff->writableTail(), payload_filler);
+
+ // create data packet
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(buff->data(), buff->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, fec::buffer payload) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(payload->data(), payload->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+};
+
+class Encoder {
+ public:
+ Encoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ if (fec_type_ == fec::FECType::UNKNOWN)
+ std::cout << "x" << fec_str << "x" << std::endl;
+ encoder_ = fec::FECUtils::getEncoder(fec_type_, 1);
+ encoder_->setFECCallback(
+ std::bind(&Encoder::onFecPackets, this, std::placeholders::_1));
+ encoder_->setBufferCallback(
+ std::bind(&Encoder::getBuffer, this, std::placeholders::_1));
+ };
+
+ ~Encoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ fec_packets_.push(packet.getBuffer());
+ }
+ }
+
+ fec::buffer getBuffer(std::size_t size) {
+ auto ret = core::PacketManager<>::getInstance()
+ .getPacket<transport::core::ContentObject>(HF_INET6_TCP, 0);
+ ret->updateLength(rtc::DATA_HEADER_SIZE + size);
+ ret->append(rtc::DATA_HEADER_SIZE + size);
+ ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ return ret;
+ }
+
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata) {
+ encoder_->onPacketProduced(content_object, offset, metadata);
+ }
+
+ public:
+ std::queue<fec::buffer> fec_packets_;
+
+ private:
+ std::unique_ptr<fec::ProducerFEC> encoder_;
+ fec::FECType fec_type_;
+};
+
+class Decoder {
+ public:
+ Decoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ decoder_ = fec::FECUtils::getDecoder(fec_type_, 1);
+ decoder_->setFECCallback(
+ std::bind(&Decoder::onFecPackets, this, std::placeholders::_1));
+ decoder_->setBufferCallback(fec::FECBase::BufferRequested(0));
+ };
+
+ ~Decoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ hicn_packet_dump(packet.getBuffer()->data(),
+ packet.getBuffer()->length());
+ recovered_packets_.push(packet.getBuffer());
+ }
+ }
+
+ void onPacketReceived(core::ContentObject &content_object, uint32_t offset) {
+ decoder_->onDataPacket(content_object, offset);
+ }
+
+ public:
+ std::queue<fec::buffer> recovered_packets_;
+
+ private:
+ std::unique_ptr<fec::ConsumerFEC> decoder_;
+ fec::FECType fec_type_;
+};
+
+TEST(FECtestRely, RelyTestInOrder1) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ // we cannot use the original data 1 to check it we recovered the packet
+ // correclty because Rely modifies the packet so here we create a copy
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 1 is lost
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestInOrder2) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ auto data2_copy = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 2 is lost
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+
+ bool eq_len = (data2_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+#if 0
+TEST(FECtestRely, RelyTestOutOfOrder1) {
+ //use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ std::cout << "dump packet 2" << std::endl;
+ hicn_packet_dump(data2->data(), data2->length());
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ std::cout << "dump packet 2" << std::endl;
+ hicn_packet_dump(data2->data(), data2->length());
+
+ std::cout << "dump packet 3" << std::endl;
+ hicn_packet_dump(data3->data(), data3->length());
+
+ // decoding ooo packets. data 1 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t) 2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if(eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int) 0);
+}
+#endif
+
+TEST(FECtestRely, RelyTestOutOfOrder2) {
+ // use Rely k = 2 N = 6
+ std::string fec_str = "Rely_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ auto data2_copy = pf.createData(name, 2, 45, 2);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 2 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+ bool eq_len = (data2_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestLargerBlocks) {
+ // use Rely k = 4 N = 7
+ std::string fec_str = "Rely_K4_N7";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+
+ auto data3 = pf.createData(name, 3, 12, 3);
+ auto data3_copy = pf.createData(name, 3, 12, 3);
+
+ auto data4 = pf.createData(name, 4, 20, 4);
+ auto data4_copy = pf.createData(name, 4, 20, 4);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data4, data4->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data5 = pf.createData(name, 5, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 5
+ encoder.fec_packets_.pop(); // pop 6
+ auto data7 = pf.createData(name, 7, encoder.fec_packets_.front());
+
+ // decoding packets: lost data 3 and data 4
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data7, data7->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data5, data5->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)4);
+ decoder.recovered_packets_.pop(); // pop data 1
+ decoder.recovered_packets_.pop(); // pop data 2
+ auto recovered3 = pf.createData(name, 3, decoder.recovered_packets_.front());
+ decoder.recovered_packets_.pop();
+ auto recovered4 = pf.createData(name, 4, decoder.recovered_packets_.front());
+
+ bool eq_len = (data3_copy->length() == recovered3->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data3_copy->data(), recovered3->data(), recovered3->length());
+ EXPECT_EQ(ret, (int)0);
+
+ eq_len = (data4_copy->length() == recovered4->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data4_copy->data(), recovered4->data(), recovered4->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRely, RelyTestK1_N3) {
+ // use Rely k = 1 N = 3
+ std::string fec_str = "Rely_K1_N3";
+ Encoder encoder(fec_str);
+ Decoder decoder1(fec_str); // recv 2
+ Decoder decoder2(fec_str); // recv 3
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ auto data1_copy = pf.createData(name, 1, 50, 1);
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packets
+ EXPECT_TRUE(encoder.fec_packets_.size() == 2);
+ auto data2 = pf.createData(name, 2, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 2
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // test1: recv data 2
+ decoder1.onPacketReceived(*data2,
+ data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ EXPECT_EQ(decoder1.recovered_packets_.size(), (size_t)1);
+
+ auto recovered = pf.createData(name, 1, decoder1.recovered_packets_.front());
+ bool eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+
+ // test2: recv data 3
+ decoder2.onPacketReceived(*data3,
+ data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ EXPECT_EQ(decoder2.recovered_packets_.size(), (size_t)1);
+
+ recovered = pf.createData(name, 1, decoder2.recovered_packets_.front());
+ eq_len = (data1_copy->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data1_copy->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_fec_base_rs.cc b/libtransport/src/test/test_fec_base_rs.cc
new file mode 100644
index 000000000..7d7bcebc3
--- /dev/null
+++ b/libtransport/src/test/test_fec_base_rs.cc
@@ -0,0 +1,412 @@
+/*
+ * 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 <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <protocols/fec_base.h>
+#include <protocols/fec_utils.h>
+#include <protocols/rtc/rtc_consts.h>
+
+#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <random>
+
+namespace transport {
+namespace protocol {
+
+class PacketFactory {
+ public:
+ PacketFactory(){};
+
+ ~PacketFactory(){};
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, uint32_t payload_size,
+ uint32_t payload_filler) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // create payload
+ auto buff = packet_manager.getMemBuf();
+ buff->append(payload_size);
+ std::fill(buff->writableData(), buff->writableTail(), payload_filler);
+
+ // create data packet
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(buff->data(), buff->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+
+ std::shared_ptr<transport::core::ContentObject> createData(
+ core::Name &name, uint32_t suffix, fec::buffer payload) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ auto data = packet_manager.getPacket<transport::core::ContentObject>(
+ HF_INET6_TCP, 0);
+ struct rtc::data_packet_t header;
+ header.setTimestamp(1000);
+ header.setProductionRate(1);
+ data->appendPayload((const uint8_t *)&header, rtc::DATA_HEADER_SIZE);
+ data->appendPayload(payload->data(), payload->length());
+ data->setName(name.setSuffix(suffix));
+ data->setLifetime(500);
+ data->setPathLabel(12);
+
+ return data;
+ }
+};
+
+class Encoder {
+ public:
+ Encoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ encoder_ = fec::FECUtils::getEncoder(fec_type_, 1);
+ encoder_->setFECCallback(
+ std::bind(&Encoder::onFecPackets, this, std::placeholders::_1));
+ encoder_->setBufferCallback(
+ std::bind(&Encoder::getBuffer, this, std::placeholders::_1));
+ };
+
+ ~Encoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ fec_packets_.push(packet.getBuffer());
+ }
+ }
+
+ fec::buffer getBuffer(std::size_t size) {
+ auto ret = core::PacketManager<>::getInstance()
+ .getPacket<transport::core::ContentObject>(HF_INET6_TCP, 0);
+ ret->updateLength(rtc::DATA_HEADER_SIZE + size);
+ ret->append(rtc::DATA_HEADER_SIZE + size);
+ ret->trimStart(ret->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ return ret;
+ }
+
+ void onPacketProduced(core::ContentObject &content_object, uint32_t offset,
+ uint32_t metadata) {
+ encoder_->onPacketProduced(content_object, offset, metadata);
+ }
+
+ public:
+ std::queue<fec::buffer> fec_packets_;
+
+ private:
+ std::unique_ptr<fec::ProducerFEC> encoder_;
+ fec::FECType fec_type_;
+};
+
+class Decoder {
+ public:
+ Decoder(std::string fec_str) {
+ fec_type_ = fec::FECUtils::fecTypeFromString(fec_str.c_str());
+ decoder_ = fec::FECUtils::getDecoder(fec_type_, 1);
+ decoder_->setFECCallback(
+ std::bind(&Decoder::onFecPackets, this, std::placeholders::_1));
+ decoder_->setBufferCallback(fec::FECBase::BufferRequested(0));
+ };
+
+ ~Decoder(){};
+
+ void onFecPackets(fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ recovered_packets_.push(packet.getBuffer());
+ }
+ }
+
+ void onPacketReceived(core::ContentObject &content_object, uint32_t offset) {
+ decoder_->onDataPacket(content_object, offset);
+ }
+
+ public:
+ std::queue<fec::buffer> recovered_packets_;
+
+ private:
+ std::unique_ptr<fec::ConsumerFEC> decoder_;
+ fec::FECType fec_type_;
+};
+
+TEST(FECtestRS, RSTestInOrder1) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 1 is lost
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestInOrder2) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decode in order, data 2 is lost
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // check recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data packet 1
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+
+ bool eq_len = (data2->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestOutOfOrder1) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 1 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ auto recovered = pf.createData(name, 1, decoder.recovered_packets_.front());
+ bool eq_len = (data1->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data1->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestOutOfOrder2) {
+ // use RS k = 2 N = 6
+ std::string fec_str = "RS_K2_N6";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data3 = pf.createData(name, 3, encoder.fec_packets_.front());
+
+ // decoding ooo packets. data 2 is lost.
+ decoder.onPacketReceived(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)2);
+ decoder.recovered_packets_.pop(); // pop data packet 1
+
+ auto recovered = pf.createData(name, 2, decoder.recovered_packets_.front());
+ bool eq_len = (data2->length() == recovered->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data2->data(), recovered->data(), recovered->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+TEST(FECtestRS, RSTestLargerBlocks) {
+ // use RS k = 4 N = 7
+ std::string fec_str = "RS_K4_N7";
+ Encoder encoder(fec_str);
+ Decoder decoder(fec_str);
+
+ PacketFactory pf;
+
+ core::Name name("b001::");
+
+ auto data1 = pf.createData(name, 1, 50, 1);
+ const uint8_t *data1_ptr = data1->data();
+
+ auto data2 = pf.createData(name, 2, 45, 2);
+ const uint8_t *data2_ptr = data2->data();
+
+ auto data3 = pf.createData(name, 3, 12, 3);
+ const uint8_t *data3_ptr = data3->data();
+
+ auto data4 = pf.createData(name, 4, 20, 4);
+ const uint8_t *data4_ptr = data4->data();
+
+ // encoding
+ uint32_t metadata = static_cast<uint32_t>(data1->getPayloadType());
+ encoder.onPacketProduced(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data3, data3->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+ encoder.onPacketProduced(*data4, data4->headerSize() + rtc::DATA_HEADER_SIZE,
+ metadata);
+
+ // create fec packet
+ auto data5 = pf.createData(name, 5, encoder.fec_packets_.front());
+ encoder.fec_packets_.pop(); // pop 5
+ encoder.fec_packets_.pop(); // pop 6
+ auto data7 = pf.createData(name, 7, encoder.fec_packets_.front());
+
+ // decoding packets: lost data 3 and data 4
+ decoder.onPacketReceived(*data2, data2->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data7, data7->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data1, data1->headerSize() + rtc::DATA_HEADER_SIZE);
+ decoder.onPacketReceived(*data5, data5->headerSize() + rtc::DATA_HEADER_SIZE);
+
+ // test payload pointers off the original packets
+ EXPECT_EQ((const uint8_t *)data1->data(), data1_ptr);
+ EXPECT_EQ((const uint8_t *)data2->data(), data2_ptr);
+ EXPECT_EQ((const uint8_t *)data3->data(), data3_ptr);
+ EXPECT_EQ((const uint8_t *)data4->data(), data4_ptr);
+
+ // get recovered packet
+ EXPECT_EQ(decoder.recovered_packets_.size(), (size_t)4);
+ decoder.recovered_packets_.pop(); // pop data 1
+ decoder.recovered_packets_.pop(); // pop data 2
+ auto recovered3 = pf.createData(name, 3, decoder.recovered_packets_.front());
+ decoder.recovered_packets_.pop(); // pop data 3
+ auto recovered4 = pf.createData(name, 4, decoder.recovered_packets_.front());
+
+ bool eq_len = (data3->length() == recovered3->length());
+ EXPECT_TRUE(eq_len);
+ int ret = -1;
+ if (eq_len)
+ ret = memcmp(data3->data(), recovered3->data(), recovered3->length());
+ EXPECT_EQ(ret, (int)0);
+
+ eq_len = (data4->length() == recovered4->length());
+ EXPECT_TRUE(eq_len);
+ ret = -1;
+ if (eq_len)
+ ret = memcmp(data4->data(), recovered4->data(), recovered4->length());
+ EXPECT_EQ(ret, (int)0);
+}
+
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_fec_reedsolomon.cc b/libtransport/src/test/test_fec_reedsolomon.cc
index c7e10d111..0973069b1 100644
--- a/libtransport/src/test/test_fec_reedsolomon.cc
+++ b/libtransport/src/test/test_fec_reedsolomon.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <gtest/gtest.h>
#include <hicn/transport/core/content_object.h>
#include <hicn/transport/core/global_object_pool.h>
@@ -30,28 +31,35 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
fec::RSEncoder encoder(k, n, seq_offset);
fec::RSDecoder decoder(k, n, seq_offset);
- std::vector<fec::buffer> tx_block(k);
- std::vector<fec::buffer> rx_block(k);
+ using BufferMetadata = std::pair<fec::buffer, uint32_t>;
+
+ std::vector<BufferMetadata> tx_block(k);
+ std::vector<BufferMetadata> rx_block(k);
int count = 0;
int run = 0;
+ // Setup random engine
+ std::random_device
+ rd; // Will be used to obtain a seed for the random number engine
+ std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
+ std::uniform_int_distribution<> dis(0, 99);
+
int iterations = 100;
auto &packet_manager = core::PacketManager<>::getInstance();
- encoder.setFECCallback(
- [&tx_block](
- std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p).second);
- }
- });
+ encoder.setFECCallback([&tx_block](fec::BufferArray &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ tx_block.emplace_back(p.getBuffer(), p.getMetadata());
+ }
+ });
decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
+ [&tx_block, &count, &k](fec::BufferArray &source_packets) {
for (int i = 0; i < k; i++) {
// Compare decoded source packets with original transmitted packets.
- if (*tx_block[i] != *source_packets[i].second) {
+ if (*tx_block[i].first != *source_packets[i].getBuffer() ||
+ tx_block[i].second != source_packets[i].getMetadata()) {
count++;
}
}
@@ -60,7 +68,7 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
do {
// Discard eventual packet appended in previous callback call
tx_block.erase(tx_block.begin() + k, tx_block.end());
- auto _seq_offet = seq_offset;
+ uint32_t _seq_offset = seq_offset;
// Initialization. Feed encoder with first k source packets
for (int i = 0; i < k; i++) {
@@ -69,45 +77,46 @@ double ReedSolomonTest(int k, int n, int seq_offset, int size) {
// Let's append a bit less than size, so that the FEC class will take care
// of filling the rest with zeros
- auto cur_size = size - (rand() % 100);
+ auto cur_size = size - dis(gen);
// Set payload, saving 2 bytes at the beginning of the buffer for encoding
// the length
packet->append(cur_size);
- packet->trimStart(2);
- std::generate(packet->writableData(), packet->writableTail(), rand);
std::fill(packet->writableData(), packet->writableTail(), i + 1);
// Set first byte of payload to seq_offset, to reorder at receiver side
- packet->writableData()[0] = uint8_t(_seq_offet++);
+ uint32_t *pkt_head = (uint32_t *)packet->writableData();
+ *pkt_head = _seq_offset++;
+
+ // Set a metadata integer
+ uint32_t metadata = dis(gen);
// Store packet in tx buffer and clear rx buffer
- tx_block[i] = std::move(packet);
+ tx_block[i] = std::make_pair(std::move(packet), metadata);
}
// Create the repair packets
for (auto &tx : tx_block) {
- encoder.consume(tx, tx->writableBuffer()[0]);
+ encoder.consume(tx.first, tx.first->writableBuffer()[0], 0, tx.second);
}
// Simulate transmission on lossy channel
- unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::vector<bool> losses(n, false);
for (int i = 0; i < n - k; i++) losses[i] = true;
int rxi = 0;
- std::shuffle(losses.begin(), losses.end(),
- std::default_random_engine(seed));
+ std::shuffle(losses.begin(), losses.end(), gen);
for (int i = 0; i < n && rxi < k; i++)
if (losses[i] == false) {
rx_block[rxi++] = tx_block[i];
if (i < k) {
// Source packet
- decoder.consumeSource(rx_block[rxi - 1],
- rx_block[rxi - 1]->data()[0]);
+ uint32_t index = *((uint32_t *)rx_block[rxi - 1].first->data());
+ decoder.consumeSource(rx_block[rxi - 1].first, index, 0,
+ rx_block[rxi - 1].second);
} else {
// Repair packet
- decoder.consumeRepair(rx_block[rxi - 1]);
+ decoder.consumeRepair(rx_block[rxi - 1].first);
}
}
@@ -126,6 +135,12 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
fec::RSEncoder encoder(k, n);
fec::RSDecoder decoder(k, n);
+ // Setup random engine
+ std::random_device
+ rd; // Will be used to obtain a seed for the random number engine
+ std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
+ std::uniform_int_distribution<> dis(0, 99);
+
auto &packet_manager = core::PacketManager<>::getInstance();
std::vector<std::pair<fec::buffer, uint32_t>> tx_block;
@@ -136,33 +151,39 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
// Receiver will receive packet for n_sourceblocks in a random order.
int total_packets = n * n_sourceblocks;
int tx_packets = k * n_sourceblocks;
- unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
- encoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &repair_packets) {
- for (auto &p : repair_packets) {
- // Append repair symbols to tx_block
- tx_block.emplace_back(std::move(p.second), ++i);
- }
+ encoder.setFECCallback([&tx_block, &rx_block, &i, &n, &k,
+ &encoder](fec::BufferArray &repair_packets) {
+ for (auto &p : repair_packets) {
+ // Append repair symbols to tx_block
+ ++i;
+ tx_block.emplace_back(std::move(p.getBuffer()), i);
+ }
- EXPECT_EQ(tx_block.size(), size_t(n));
+ EXPECT_EQ(tx_block.size(), size_t(n));
- // Select k packets to send, including at least one symbol. We start
- // from the end for this reason.
- for (int j = n - 1; j > n - k - 1; j--) {
- rx_block.emplace_back(std::move(tx_block[j]));
- }
+ // Select k packets to send, including at least one symbol. We start
+ // from the end for this reason.
+ for (int j = n - 1; j > n - k - 1; j--) {
+ rx_block.emplace_back(std::move(tx_block[j]));
+ }
- // Clear tx block for next source block
- tx_block.clear();
- encoder.clear();
- });
+ // Clear tx block for next source block
+ tx_block.clear();
+ encoder.clear();
+ });
// The decode callback must be called exactly n_sourceblocks times
- decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &source_packets) {
- count++;
- });
+ decoder.setFECCallback([&count](fec::BufferArray &source_packets) {
+ // Check buffers
+ for (auto &packet : source_packets) {
+ auto packet_index = ((uint32_t *)packet.getBuffer()->writableData())[0];
+ EXPECT_EQ(packet_index, packet.getIndex())
+ << "Packet index: " << packet_index
+ << " -- FEC Index: " << packet.getIndex();
+ }
+ count++;
+ });
// Produce n * n_sourceblocks
// - ( k ) * n_sourceblocks source packets
@@ -173,7 +194,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
// Let's append a bit less than size, so that the FEC class will take care
// of filling the rest with zeros
- auto cur_size = size - (rand() % 100);
+ auto cur_size = size - dis(gen);
// Set payload, saving 2 bytes at the beginning of the buffer for encoding
// the length
@@ -182,7 +203,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
std::fill(packet->writableData(), packet->writableTail(), i + 1);
// Set first byte of payload to i, to reorder at receiver side
- packet->writableData()[0] = uint8_t(i);
+ ((uint32_t *)packet->writableData())[0] = uint32_t(i);
// Store packet in tx buffer
tx_block.emplace_back(packet, i);
@@ -195,8 +216,7 @@ void ReedSolomonMultiBlockTest(int n_sourceblocks) {
EXPECT_EQ(size_t(tx_packets), size_t(rx_block.size()));
// Lets shuffle the rx_block before starting feeding the decoder.
- std::shuffle(rx_block.begin(), rx_block.end(),
- std::default_random_engine(seed));
+ std::shuffle(rx_block.begin(), rx_block.end(), gen);
for (auto &p : rx_block) {
int index = p.second % n;
@@ -231,7 +251,7 @@ foreach_rs_fec_type
#undef _
TEST(ReedSolomonMultiBlockTest, RSMB10) {
- int blocks = 10;
+ int blocks = 1;
ReedSolomonMultiBlockTest(blocks);
}
diff --git a/libtransport/src/test/test_fec_rely_wrapper.cc b/libtransport/src/test/test_fec_rely_wrapper.cc
index c5b73f8d2..764e4dd2d 100644
--- a/libtransport/src/test/test_fec_rely_wrapper.cc
+++ b/libtransport/src/test/test_fec_rely_wrapper.cc
@@ -13,18 +13,23 @@
* limitations under the License.
*/
+#include <glog/logging.h>
#include <gtest/gtest.h>
#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
#include <hicn/transport/utils/log.h>
#include <protocols/fec/rely.h>
#include <queue>
+#include <random>
namespace transport {
namespace protocol {
-std::string printMissing(
- const std::map<uint32_t, core::ContentObject::Ptr> &missing) {
+using SavedPacketMap =
+ std::map<uint32_t, std::pair<core::ContentObject::Ptr, uint32_t>>;
+
+std::string printMissing(const SavedPacketMap &missing) {
std::stringstream stream;
for (auto &[seq, packet] : missing) {
@@ -48,14 +53,15 @@ std::string printMissing(
* @param loss_rate The loss rate
*/
void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
- int64_t timeout, uint32_t max_iterations,
+ int64_t /* timeout */, uint32_t max_iterations,
int loss_rate) {
// Create 1 encoder and 1 decoder
fec::RelyEncoder _encoder(k, n);
fec::RelyDecoder _decoder(k, n);
// Seed the pseudo-random with known value to always get same loss pattern
- srand(k * n);
+ std::mt19937 gen(k *
+ n); // Standard mersenne_twister_engine seeded with rd();
// We will interact with rely encoder/decoder using the interface
fec::ProducerFEC &encoder = _encoder;
@@ -68,73 +74,78 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
auto &packet_manager = core::PacketManager<>::getInstance();
// Store packets to verify them in the decoder callback
- std::map<uint32_t, core::ContentObject::Ptr> saved_packets;
+ SavedPacketMap saved_packets;
// Save repair packets here in encoder callback
std::queue<fec::buffer> pending_repair_packets;
// Set callback called by encoder when a buffer is required.
- encoder.setBufferCallback([](std::size_t size) -> fec::buffer {
+ encoder.setBufferCallback([](std::size_t size) {
auto ret =
- core::PacketManager<>::getInstance().getPacket<core::ContentObject>();
+ core::PacketManager<>::getInstance().getPacket<core::ContentObject>(
+ transport::interface::default_values::packet_format);
ret->updateLength(size);
ret->append(size);
ret->trimStart(ret->headerSize());
- assert(ret->length() >= size);
+ DCHECK(ret->length() >= size);
return ret;
});
// Set callback to be called by encoder when repair packets are ready
- encoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
- // We must get n - k symbols
- EXPECT_EQ(packets.size(), n - k);
- // TRANSPORT_LOGD("Got %zu symbols", packets.size());
-
- // Save symbols in pending_repair_packets queue and increment iterations
- for (auto &packet : packets) {
- ++iterations;
- pending_repair_packets.push(packet.second);
- }
- });
+ encoder.setFECCallback([&iterations, &pending_repair_packets, &n,
+ &k](fec::BufferArray &packets) {
+ // We must get n - k symbols
+ EXPECT_EQ(packets.size(), n - k);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Got " << packets.size() << " symbols";
+
+ // Save symbols in pending_repair_packets queue and increment iterations
+ for (auto &packet : packets) {
+ ++iterations;
+ pending_repair_packets.push(packet.getBuffer());
+ }
+ });
// Set callback to be called when decoder recover a packet
- decoder.setFECCallback(
- [&](std::vector<std::pair<uint32_t, fec::buffer>> &packets) {
- for (auto &packet : packets) {
- // TRANSPORT_LOGD("Recovering packet %u", packet.first);
+ decoder.setFECCallback([&saved_packets](fec::BufferArray &packets) {
+ for (auto &packet : packets) {
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Recovering packet " << packet.getIndex();
+
+ // Ensure recovered packet is in packets actually produced by encoder
+ auto original = saved_packets.find(packet.getIndex());
+ ASSERT_TRUE(original != saved_packets.end());
+ auto &original_packet = *original->second.first;
- // Ensure recovered packet is in packets actually produced by encoder
- auto original = saved_packets.find(packet.first);
- ASSERT_TRUE(original != saved_packets.end());
- auto &original_packet = *original->second;
+ // Remove additional headers at the beginning of the packet. This may
+ // change in the future.
+ original_packet.trimStart(60 /* Ip + TCP */ + 32 /* Rely header */ +
+ 4 /* Packet size */);
- // Remove additional headers at the beginning of the packet. This may
- // change in the future.
- original_packet.trimStart(60 /* Ip + TCP */ + 28 /* Rely header */ +
- 4 /* Packet size */);
+ // Recovered packet should be equal to the original one
+ EXPECT_TRUE(original_packet == *packet.getBuffer());
- // Recovered packet should be equal to the original one
- EXPECT_TRUE(original_packet == *packet.second);
+ // Also metadata should correspond
+ EXPECT_TRUE(original->second.second == packet.getMetadata());
- // Restore removed headers
- original_packet.prepend(60 + 28 + 4);
+ // Restore removed headers
+ original_packet.prepend(60 + 32 + 4);
- // Erase packet from saved packet list
- saved_packets.erase(original);
- }
- });
+ // Erase packet from saved packet list
+ saved_packets.erase(original);
+ }
+ });
// Send max_iterations packets from encoder to decoder
+ std::uniform_int_distribution<> dis(0, 1299);
while (iterations < max_iterations) {
// Create a payload, the size is between 50 and 1350 bytes.
- auto payload_size = 50 + (rand() % 1300);
+ auto payload_size = 50 + (dis(gen));
uint8_t payload[max_packet_size];
- std::generate(payload, payload + payload_size, rand);
+ std::generate(payload, payload + payload_size, gen);
// Get a packet from global pool and set name
- auto buffer = packet_manager.getPacket<core::ContentObject>();
+ auto buffer = packet_manager.getPacket<core::ContentObject>(
+ transport::interface::default_values::packet_format);
buffer->setName(core::Name("b001::abcd", iterations));
// Get offset
@@ -145,20 +156,23 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// its own header).
buffer->appendPayload(payload, payload_size);
+ // Set an u32 metadata to pass altogether with the buffer
+ uint32_t metadata = dis(gen);
+
// Save packet in the saving_packets list
- // TRANSPORT_LOGD("Saving packet with index %lu", iterations);
- saved_packets.emplace(iterations, buffer);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Saving packet with index " << iterations;
+ saved_packets.emplace(iterations, std::make_pair(buffer, metadata));
// Feed buffer into the encoder. This will eventually trigger a call to the
// FEC callback as soon as k packets are fed into the endocer.
- encoder.onPacketProduced(*buffer, offset);
+ encoder.onPacketProduced(*buffer, offset, metadata);
// Check returned packet. We calculate the difference in size and we compare
// only the part of the returned packet corresponding to the original
// payload. Rely should only add a header and should not modify the actual
// payload content. If it does it, this check will fail.
auto diff = buffer->length() - payload_size - offset;
- // TRANSPORT_LOGD("Difference is %zu", diff);
+ DLOG_IF(INFO, VLOG_IS_ON(3)) << "Difference is " << diff;
auto cmp =
std::memcmp(buffer->data() + offset + diff, payload, payload_size);
EXPECT_FALSE(cmp);
@@ -170,29 +184,33 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// using future packets that are not created in the test. For this reason,
// we ensure the test ends without losses.
#define DROP_CONDITION(loss_rate, max_iterations) \
- (rand() % 100) >= loss_rate || iterations >= max_iterations * 0.9
+ (dis(gen)) >= loss_rate || iterations >= max_iterations * 0.9
// Handle the source packet to the decoder, id drop condition returns true
if (DROP_CONDITION(loss_rate, max_iterations)) {
// Pass packet to decoder
- // TRANSPORT_LOGD("Passing packet %u to decoder",
- // buffer->getName().getSuffix());
- decoder.onDataPacket(*buffer, offset);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Passing packet " << buffer->getName().getSuffix()
+ << " to decoder";
+ decoder.onDataPacket(*buffer, offset, metadata);
} else {
- // TRANSPORT_LOGD("Packet %u, dropped", buffer->getName().getSuffix());
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet " << buffer->getName().getSuffix() << " dropped";
}
- // Check if previous call to encoder.consumer() generated repair packets,
+ // Check if previous call to encoder.consume() generated repair packets,
// and if yes, feed them to the decoder.
while (pending_repair_packets.size()) {
// Also repair packets can be lost
if (DROP_CONDITION(loss_rate, max_iterations)) {
auto &packet = pending_repair_packets.front();
- // TRANSPORT_LOGD("Passing packet %u to decoder", iterations);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Passing packet " << iterations << " to decoder";
core::ContentObject &co = (core::ContentObject &)(*packet);
decoder.onDataPacket(co, 0);
} else {
- // TRANSPORT_LOGD("Packet (repair) %u dropped", iterations);
+ DLOG_IF(INFO, VLOG_IS_ON(3))
+ << "Packet (repair) " << iterations << " dropped";
}
// Remove packet from the queue
@@ -206,9 +224,6 @@ void testRelyEncoderDecoder(uint32_t k, uint32_t n, size_t max_packet_size,
// 0.001 residual losses
EXPECT_LE(saved_packets.size(), iterations * 0.001)
<< printMissing(saved_packets);
-
- // Reset seed
- srand(time(0));
}
/**
diff --git a/libtransport/src/test/test_fixed_block_allocator.cc b/libtransport/src/test/test_fixed_block_allocator.cc
new file mode 100644
index 000000000..33e048031
--- /dev/null
+++ b/libtransport/src/test/test_fixed_block_allocator.cc
@@ -0,0 +1,211 @@
+/*
+ * 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 <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/fixed_block_allocator.h>
+
+namespace utils {
+
+class FixedBlockAllocatorTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ FixedBlockAllocatorTest()
+ : allocator_(
+ ::utils::FixedBlockAllocator<default_size,
+ default_n_buffer>::getInstance()) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~FixedBlockAllocatorTest() {
+ // 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).
+ allocator_.reset();
+ }
+
+ virtual void TearDown() {
+ // Code here will be called immediately after each test (right
+ // before the destructor).
+ allocator_.reset();
+ }
+
+ static bool pointerIsAligned(const void *pointer, size_t byte_count) {
+ // Sanity check
+ EXPECT_THAT(reinterpret_cast<std::uintptr_t>(pointer) &
+ (alignof(std::max_align_t) - 1),
+ testing::Eq(std::uintptr_t(0)));
+
+ return uintptr_t(pointer) % byte_count == 0;
+ }
+
+ ::utils::FixedBlockAllocator<default_size, default_n_buffer> &allocator_;
+};
+
+TEST_F(FixedBlockAllocatorTest, DefaultChecks) {
+ EXPECT_EQ(allocator_.blockSize(), default_size);
+ EXPECT_EQ(allocator_.blockCount(), default_n_buffer);
+ EXPECT_EQ(allocator_.allocations(), 0UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+
+ // Allocate one single block of memory
+ auto block = allocator_.allocateBlock();
+
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Check statistics
+ EXPECT_EQ(allocator_.allocations(), 1UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 1UL);
+
+ // Deallocate it
+ allocator_.deallocateBlock(block);
+
+ // check statistics
+ EXPECT_EQ(allocator_.allocations(), 1UL);
+ EXPECT_EQ(allocator_.deallocations(), 1UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+
+ // Test reset
+ allocator_.reset();
+
+ EXPECT_EQ(allocator_.blockSize(), default_size);
+ EXPECT_EQ(allocator_.blockCount(), default_n_buffer);
+ EXPECT_EQ(allocator_.allocations(), 0UL);
+ EXPECT_EQ(allocator_.deallocations(), 0UL);
+ EXPECT_EQ(allocator_.blocksInUse(), 0UL);
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsReused) {
+ // Get one block. As it is the first one, it will be retrieved from the pool
+ auto block = allocator_.allocateBlock();
+
+ // Make sure block is valid
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Release block
+ allocator_.deallocateBlock(block);
+
+ // Get same memory block again
+ auto block2 = allocator_.allocateBlock();
+
+ // Make sure memory is reused
+ ASSERT_EQ(block, block2);
+
+ // Get a third block
+ auto block3 = allocator_.allocateBlock();
+
+ // Make sure is different memory
+ ASSERT_NE(block2, block3);
+
+ // Deallocate both and check we get back the laso one
+ allocator_.deallocateBlock(block2);
+ allocator_.deallocateBlock(block3);
+
+ auto block4 = allocator_.allocateBlock();
+ ASSERT_EQ(block3, block4);
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsContiguous) {
+ // Get one block. As it is the first one, it will be retrieved from the pool
+ auto block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure block is valid
+ ASSERT_THAT(block, testing::NotNull());
+
+ // Get another block
+ auto block2 = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure block is valid
+ ASSERT_THAT(block2, testing::NotNull());
+
+ // Check the 2 blocks come from contiguous memory
+ ASSERT_THAT(std::size_t(block2 - block), testing::Eq(default_size));
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckPoolExpansion) {
+ // Get all the blocks we setup when constructing the allocator
+ std::array<uint8_t *, default_n_buffer> blocks;
+ blocks[0] = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ for (std::size_t i = 1; i < default_n_buffer; i++) {
+ blocks[i] = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ ASSERT_THAT(std::size_t(blocks[i] - blocks[i - 1]),
+ testing::Eq(default_size));
+ }
+
+ ASSERT_THAT(allocator_.blockCount(), testing::Eq(default_n_buffer));
+
+ // We should have finished all the blocks belonging to first pool. Let's get
+ // one additional block
+ auto new_block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+
+ // Make sure the block count doubled its size
+ ASSERT_THAT(allocator_.blockCount(), testing::Eq(2 * default_n_buffer));
+
+ // Check the new block is not contiguous with respect last block in blocks
+ ASSERT_THAT(std::size_t(new_block - blocks[default_n_buffer - 1]),
+ testing::Ne(default_size));
+}
+
+TEST_F(FixedBlockAllocatorTest, CheckMemoryIsAligned) {
+ for (std::size_t i = 0; i < default_n_buffer; i++) {
+ auto block = reinterpret_cast<uint8_t *>(allocator_.allocateBlock());
+ ASSERT_THAT(pointerIsAligned(block, alignof(std::max_align_t)),
+ testing::IsTrue);
+ }
+}
+
+TEST_F(FixedBlockAllocatorTest, Multithreading) {
+ // Create 4 threads
+ utils::EventThread threads[4];
+ ::utils::FixedBlockAllocator<default_size, default_n_buffer>
+ *allocator_addresses[4] = {nullptr, nullptr, nullptr, nullptr};
+ int i = 0;
+ for (auto &t : threads) {
+ t.add([&allocator_addresses, i]() {
+ auto &allocator =
+ ::utils::FixedBlockAllocator<default_size,
+ default_n_buffer>::getInstance();
+ allocator_addresses[i] = &allocator;
+ });
+ i++;
+ }
+
+ // Stop threads
+ for (auto &t : threads) {
+ t.stop();
+ }
+
+ // Check the instance of allocator was different for each thread
+ for (int i = 0; i < 4; i++) {
+ for (int j = i + 1; j < 4; j++) {
+ ASSERT_NE(allocator_addresses[i], allocator_addresses[j]);
+ }
+ }
+}
+
+} // namespace utils \ No newline at end of file
diff --git a/libtransport/src/test/test_interest.cc b/libtransport/src/test/test_interest.cc
index 8853563b0..d9c535881 100644
--- a/libtransport/src/test/test_interest.cc
+++ b/libtransport/src/test/test_interest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * 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:
@@ -30,7 +30,7 @@ namespace {
// The fixture for testing class Foo.
class InterestTest : public ::testing::Test {
protected:
- InterestTest() : name_("b001::123|321"), interest_() {
+ InterestTest() : name_("b001::123|321"), interest_(HF_INET6_TCP) {
// You can do set-up work for each test here.
}
@@ -108,7 +108,7 @@ TEST_F(InterestTest, ConstructorWithName) {
Name n("b001::1|123");
try {
- Interest interest(n);
+ Interest interest(HF_INET6_TCP, n);
} catch (...) {
FAIL() << "ERROR: Unexpected exception thrown";
}
@@ -176,27 +176,27 @@ TEST_F(InterestTest, SetGetLocator) {
auto l = interest.getLocator();
ip_address_t address;
- ip_address_pton("b006::ab:cdab:cdef", &address);
- auto ret = !std::memcmp(&l, &address, sizeof(address));
+ inet_pton(AF_INET6, "b006::ab:cdab:cdef", &address);
+ auto ret = !ip_address_cmp(&l, &address, AF_INET6);
EXPECT_TRUE(ret);
// Set different locator
- ip_address_pton("2001::1234::4321::abcd::", &address);
+ inet_pton(AF_INET6, "2001::1234::4321::abcd::", &address);
// Set it on interest
interest.setLocator(address);
// Check it was set
l = interest.getLocator();
- ret = !std::memcmp(&l, &address, sizeof(address));
+ ret = !ip_address_cmp(&l, &address, AF_INET6);
EXPECT_TRUE(ret);
}
TEST_F(InterestTest, SetGetLifetime) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
const constexpr uint32_t lifetime = 10000;
// Set lifetime
@@ -211,7 +211,7 @@ TEST_F(InterestTest, SetGetLifetime) {
TEST_F(InterestTest, HasManifest) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
// Let's expect anexception here
try {
@@ -232,7 +232,7 @@ TEST_F(InterestTest, HasManifest) {
TEST_F(InterestTest, AppendSuffixesEncodeAndIterate) {
// Create interest from buffer
- Interest interest;
+ Interest interest(HF_INET6_TCP);
// Appenad some suffixes, with some duplicates
interest.appendSuffix(1);
diff --git a/libtransport/src/test/test_memif_connector.cc b/libtransport/src/test/test_memif_connector.cc
new file mode 100644
index 000000000..562a12c88
--- /dev/null
+++ b/libtransport/src/test/test_memif_connector.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <core/memif_connector.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/global_object_pool.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
+
+namespace transport {
+namespace core {
+
+namespace {
+
+using namespace std::placeholders;
+
+/**
+ * Master memif connector
+ */
+template <int Master>
+class Memif {
+ static inline std::size_t counter = 256;
+ static inline std::size_t total_packets = counter * 4096;
+ static inline std::size_t packet_size = 64;
+
+ public:
+ Memif(asio::io_service &io_service)
+ : io_service_(io_service),
+ memif_connector_(std::make_shared<MemifConnector>(
+ std::bind(&Memif::onPacketReceived, this, _1, _2, _3),
+ std::bind(&Memif::onPacketSent, this, _1, _2),
+ std::bind(&Memif::onClose, this, _1),
+ std::bind(&Memif::onReconnect, this, _1, _2), io_service_,
+ Master ? "test_master" : "test_slave")),
+ recv_counter_(0),
+ sent_counter_(0) {
+ memif_connector_->connect(0 /* Memif ID */, Master /* Is Master */,
+ "@hicntransport/test/memif");
+ }
+
+ void setStart() { t0_ = utils::SteadyTime::now(); }
+
+ void startTest() {
+ if constexpr (!Master) {
+ auto &packet_manager = core::PacketManager<>::getInstance();
+
+ // Send in busrt of 256 packet per time
+ for (std::size_t i = 0; i < counter; i++) {
+ auto packet = packet_manager.getMemBuf();
+ packet->append(packet_size);
+ memif_connector_->send(packet);
+ sent_counter_++;
+ }
+
+ if (sent_counter_ < total_packets) {
+ asio::post(io_service_, std::bind(&Memif::startTest, this));
+ }
+ } else {
+ setStart();
+ }
+ }
+
+ auto getRecvCounter() { return recv_counter_; }
+ auto getSentCounter() { return sent_counter_; }
+
+ private:
+ void onPacketReceived(Connector *c,
+ const std::vector<utils::MemBuf::Ptr> &buffers,
+ const std::error_code &ec) {
+ if constexpr (Master) {
+ recv_counter_ += buffers.size();
+ if (recv_counter_ == total_packets) {
+ auto t1 = utils::SteadyTime::now();
+ auto delta = utils::SteadyTime::getDurationS(t0_, t1);
+ auto rate = recv_counter_ / delta.count();
+ LOG(INFO) << "rate: " << rate << " packets/s";
+ io_service_.stop();
+ }
+ } else {
+ FAIL() << "Slave should not receive packets";
+ }
+ }
+ void onPacketSent(Connector *c, const std::error_code &ec) {}
+ void onClose(Connector *c) {}
+ void onReconnect(Connector *c, const std::error_code &ec) {}
+
+ private:
+ asio::io_service &io_service_;
+ std::shared_ptr<MemifConnector> memif_connector_;
+ std::size_t recv_counter_;
+ std::size_t sent_counter_;
+ utils::SteadyTime::TimePoint t0_;
+};
+
+using MemifMaster = Memif<1>;
+using MemifSlave = Memif<0>;
+
+} // namespace
+
+class MemifTest : public ::testing::Test {
+ protected:
+ MemifTest() : io_service_(), master_(io_service_), slave_(io_service_) {
+ // You can do set-up work for each test here.
+ }
+
+ void run() {
+ asio::post(io_service_, std::bind(&MemifSlave::startTest, &slave_));
+ master_.startTest();
+ io_service_.run();
+
+ EXPECT_THAT(master_.getRecvCounter(),
+ ::testing::Eq(slave_.getSentCounter()));
+ }
+
+ virtual ~MemifTest() {
+ // 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).
+ }
+
+ protected:
+ asio::io_service io_service_;
+ MemifMaster master_;
+ MemifSlave slave_;
+};
+
+TEST_F(MemifTest, Test) { run(); }
+} // namespace core
+} // namespace transport
diff --git a/libtransport/src/test/test_packet.cc b/libtransport/src/test/test_packet.cc
index 76ad352d6..ca20cdfb7 100644
--- a/libtransport/src/test/test_packet.cc
+++ b/libtransport/src/test/test_packet.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * 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:
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
#include <hicn/transport/core/packet.h>
#include <hicn/transport/errors/not_implemented_exception.h>
+#include <hicn/transport/utils/chrono_typedefs.h>
#include <test/packet_samples.h>
#include <climits>
@@ -33,7 +34,7 @@ namespace core {
class PacketForTest : public Packet {
public:
template <typename... Args>
- PacketForTest(Args &&... args) : Packet(std::forward<Args>(args)...) {}
+ PacketForTest(Args &&...args) : Packet(std::forward<Args>(args)...) {}
virtual ~PacketForTest() {}
@@ -302,7 +303,7 @@ TEST_F(PacketTest, ConstructorWithNew) {
auto &_packet = raw_packets_[HF_INET6_TCP];
auto packet_ptr = new PacketForTest(Packet::WRAP_BUFFER, &_packet[0],
_packet.size(), _packet.size());
- (void)packet_ptr;
+ delete packet_ptr;
}
TEST_F(PacketTest, ConstructorWithRawBufferInet6Tcp) {
@@ -682,9 +683,7 @@ TEST_F(PacketTest, SetGetTestSignatureTimestamp) {
// Let's try to set the signature timestamp in a packet without AH header. We
// expect an exception.
using namespace std::chrono;
- uint64_t now =
- duration_cast<milliseconds>(system_clock::now().time_since_epoch())
- .count();
+ uint64_t now = utils::SteadyTime::nowMs().count();
try {
packet.setSignatureTimestamp(now);
diff --git a/libtransport/src/test/test_packet_allocator.cc b/libtransport/src/test/test_packet_allocator.cc
new file mode 100644
index 000000000..b63ddde8d
--- /dev/null
+++ b/libtransport/src/test/test_packet_allocator.cc
@@ -0,0 +1,106 @@
+/*
+ * 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 <glog/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/interest.h>
+#define ALLOCATION_CHECKS
+#include <hicn/transport/core/global_object_pool.h>
+#undef ALLOCATION_CHECKS
+#include <hicn/transport/utils/event_thread.h>
+
+namespace transport {
+namespace core {
+
+class PacketAllocatorTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ PacketAllocatorTest() : allocator_(PacketManager<>::getInstance()) {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~PacketAllocatorTest() {
+ // 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() {}
+
+ virtual void TearDown() {}
+
+ static bool pointerIsAligned(const void *pointer, size_t byte_count) {
+ return uintptr_t(pointer) % byte_count == 0;
+ }
+
+ template <typename T, typename... Args>
+ void allocationTest(Args &&...args) {
+ // Create packet
+ auto packet = allocator_.getPacket<T>(std::forward<Args>(args)...);
+
+ // Check boundaries
+ LOG(INFO) << "packet size: " << sizeof(*packet) + sizeof(packet)
+ << std::endl;
+ EXPECT_LE(sizeof(*packet) + sizeof(packet) + sizeof(std::max_align_t),
+ sizeof(PacketManager<>::PacketStorage::packet_and_shared_ptr));
+ }
+
+ PacketManager<> &allocator_;
+};
+
+TEST_F(PacketAllocatorTest, ContentObjectAllocation) {
+ allocationTest<core::ContentObject>(HF_INET_TCP);
+}
+
+TEST_F(PacketAllocatorTest, InterestAllocation) {
+ allocationTest<core::Interest>(HF_INET_TCP);
+}
+
+// TEST_F(PacketAllocatorTest, MemBufAllocation) {
+// allocationTest<::utils::MemBuf>();
+// }
+
+TEST_F(PacketAllocatorTest, CheckAllocationIsCorrect) {
+ // Create packet
+ auto packet = allocator_.getPacket<core::ContentObject>(HF_INET_TCP);
+
+ // Address of actual buffer
+ uint8_t *buffer_address = packet->writableData();
+
+ // Address of packet
+ uint8_t *packet_address = reinterpret_cast<uint8_t *>(packet.get());
+
+ uint8_t *start_address =
+ buffer_address -
+ sizeof(PacketManager<>::PacketStorage::packet_and_shared_ptr);
+
+ // Check memory was allocated on correct positions
+ EXPECT_TRUE(pointerIsAligned(start_address, alignof(std::max_align_t)));
+ EXPECT_TRUE(packet_address > start_address &&
+ packet_address < buffer_address);
+ EXPECT_TRUE(pointerIsAligned(buffer_address, alignof(std::max_align_t)));
+ EXPECT_THAT(std::size_t(buffer_address - start_address),
+ testing::Eq(sizeof(
+ PacketManager<>::PacketStorage::packet_and_shared_ptr)));
+}
+
+} // namespace core
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/test/test_quality_score.cc b/libtransport/src/test/test_quality_score.cc
new file mode 100644
index 000000000..9513c94a6
--- /dev/null
+++ b/libtransport/src/test/test_quality_score.cc
@@ -0,0 +1,135 @@
+/*
+ * 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 <hicn/transport/utils/rtc_quality_score.h>
+
+#include <climits>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace protocol {
+
+namespace rtc {
+
+TEST(QualityScoreTest, testQS) {
+ RTCQualityScore qs;
+ uint8_t score;
+
+ // 0 losses
+ score = qs.getQualityScore(0, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(98, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(188, 0);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(398, 0);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(400, 0);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(598, 0);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(600, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(700, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(50000, 0);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // 0 delay
+ score = qs.getQualityScore(0, 2);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 9);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 29);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(0, 30);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(0, 39);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(0, 40);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(0, 50);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(0, 5000);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 10
+ score = qs.getQualityScore(0, 3);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(98, 9);
+ EXPECT_EQ(score, (uint8_t)4);
+
+ score = qs.getQualityScore(100, 9);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(398, 5);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(400, 5);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(4000, 5);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 20
+ score = qs.getQualityScore(0, 10);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(30, 10);
+ EXPECT_EQ(score, (uint8_t)3);
+
+ score = qs.getQualityScore(198, 15);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(200, 19);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ score = qs.getQualityScore(300, 10);
+ EXPECT_EQ(score, (uint8_t)1);
+
+ // loss < 30
+
+ score = qs.getQualityScore(0, 29);
+ EXPECT_EQ(score, (uint8_t)5);
+
+ score = qs.getQualityScore(10, 29);
+ EXPECT_EQ(score, (uint8_t)2);
+
+ score = qs.getQualityScore(0, 100);
+ EXPECT_EQ(score, (uint8_t)1);
+}
+
+} // namespace rtc
+} // namespace protocol
+} // namespace transport
diff --git a/libtransport/src/test/test_sessions.cc b/libtransport/src/test/test_sessions.cc
new file mode 100644
index 000000000..d2e8c27bb
--- /dev/null
+++ b/libtransport/src/test/test_sessions.cc
@@ -0,0 +1,77 @@
+/*
+ * 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 <hicn/transport/interfaces/global_conf_interface.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+namespace transport {
+namespace interface {
+
+class SessionsTest : public ::testing::Test {
+ protected:
+ static inline const std::size_t default_size = 2048;
+ static inline const std::size_t default_n_buffer = 1024;
+
+ // Get fixed block allocator_ of 1024 buffers of size 2048 bytes
+ SessionsTest() {
+ // You can do set-up work for each test here.
+ // Set io_module to local forwarder with no external connections
+ global_config::IoModuleConfiguration config;
+ config.name = "forwarder_module";
+ config.set();
+ }
+
+ virtual ~SessionsTest() {
+ // 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).
+ }
+
+ std::vector<ConsumerSocket> consumers_;
+ std::vector<ProducerSocket> producers_;
+};
+
+TEST_F(SessionsTest, SessionAllocations) {
+ // Create 1000 consumer sockets and 1000 producer sockets
+ int cprotocol = TransportProtocolAlgorithms::RAAQM;
+ int pprotocol = ProductionProtocolAlgorithms::BYTE_STREAM;
+ int offset = 0;
+
+ for (int i = 0; i < 1000; i++) {
+ auto &c = consumers_.emplace_back(cprotocol + (offset % 3));
+ auto &p = producers_.emplace_back(pprotocol + (offset % 2));
+ c.connect();
+ p.connect();
+ offset++;
+ }
+}
+
+} // namespace interface
+} // namespace transport \ No newline at end of file
diff --git a/libtransport/src/test/test_thread_pool.cc b/libtransport/src/test/test_thread_pool.cc
new file mode 100644
index 000000000..1b6b4cc81
--- /dev/null
+++ b/libtransport/src/test/test_thread_pool.cc
@@ -0,0 +1,70 @@
+/*
+ * 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 <hicn/transport/utils/thread_pool.h>
+
+namespace utils {
+
+class ThreadPoolTest : public ::testing::Test {
+ protected:
+ ThreadPoolTest() : thread_pool_() {
+ // You can do set-up work for each test here.
+ }
+
+ virtual ~ThreadPoolTest() {
+ // 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).
+ }
+
+ ::utils::ThreadPool thread_pool_;
+};
+
+TEST_F(ThreadPoolTest, DefaultConstructor) {
+ // EXPECT_EQ(thread_pool_.GetNumThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumIdleThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumBusyThreads(), 0);
+}
+
+TEST_F(ThreadPoolTest, GetNThreads) {
+ auto n_threads = thread_pool_.getNThreads();
+ EXPECT_GT(n_threads, std::size_t(0));
+ EXPECT_EQ(n_threads, std::thread::hardware_concurrency());
+
+ ::utils::ThreadPool pool(64);
+ n_threads = pool.getNThreads();
+ EXPECT_GT(n_threads, std::size_t(0));
+ EXPECT_NE(n_threads, std::thread::hardware_concurrency());
+ EXPECT_EQ(n_threads, std::size_t(64));
+
+ // EXPECT_EQ(thread_pool_.GetNumThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumIdleThreads(), 0);
+ // EXPECT_EQ(thread_pool_.GetNumBusyThreads(), 0);
+}
+
+} // namespace utils \ No newline at end of file