From ff9e916338f56e7f29531155be6bda4e1f437cbf Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 25 Oct 2018 19:07:55 +0200 Subject: [PATCH] Added Unit tests, including test from issue #468 --- .appveyor.yml | 8 +++- .travis.yml | 1 + CMakeLists.txt | 39 +++++++++++++++- scripts/googletest-download.cmake | 19 ++++++++ scripts/googletest.cmake | 32 +++++++++++++ srtcore/buffer.cpp | 10 ++--- srtcore/buffer.h | 5 ++- test/test_buffer.cpp | 11 +++++ test/test_connection_timeout.cpp | 74 +++++++++++++++++++++++++++++++ 9 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 scripts/googletest-download.cmake create mode 100644 scripts/googletest.cmake create mode 100644 test/test_buffer.cpp create mode 100644 test/test_connection_timeout.cpp diff --git a/.appveyor.yml b/.appveyor.yml index f4ceb21f5..56e4f29ca 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,8 +6,8 @@ configuration: - Debug image: - - Visual Studio 2013 - Visual Studio 2015 + - Visual Studio 2013 platform: - x64 @@ -24,9 +24,13 @@ build_script: - ps: cp C:/pthread-src/bin/x64_MSVC${VS_VERSION}.${Env:CONFIGURATION}/pthread_lib.lib C:/pthread-win32/lib # build SRT - ps: if ( $VS_VERSION -eq "2013" ) { $CMAKE_GENERATOR = "Visual Studio 12 2013 Win64" } else { $CMAKE_GENERATOR = "Visual Studio 14 2015 Win64" } - - ps: cmake . -G"$CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=$Env:CONFIGURATION + - ps: if ( $VS_VERSION -eq "2013" ) { $ENABLE_UNITTESTS = "OFF" } else { $ENABLE_UNITTESTS = "ON" } + - ps: cmake . -G"$CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=$Env:CONFIGURATION -DENABLE_UNITTESTS="$ENABLE_UNITTESTS" - ps: msbuild SRT.sln /p:Configuration=$Env:CONFIGURATION /p:Platform=x64 +test_script: + - ps: if ( $VS_VERSION -ne "2013" ) { ctest --extra-verbose -C $Env:CONFIGURATION } + after_build: - cmd: >- scripts/gather-package.bat diff --git a/.travis.yml b/.travis.yml index e2fd8334b..ceedb87cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,3 +50,4 @@ script: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DOPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR" -DCMAKE_SYSTEM_NAME="$CMAKE_SYSTEM_NAME"; fi - if [ "$TRAVIS_OS_NAME" == "osx" ]; then cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_PREFIX_PATH=/usr/local/opt/openssl; fi - make + - if [ "$TRAVIS_COMPILER" != "x86_64-w64-mingw32-g++" ]; then ctest --extra-verbose; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 071457cb0..40c16331c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,11 @@ else() set (CMAKE_BUILD_TYPE "Release") endif() +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) + message(STATUS "BUILD TYPE: ${CMAKE_BUILD_TYPE}") +message(STATUS "BINARY_DIR: ${CMAKE_BINARY_DIR}") +message(STATUS "EXECUTABLE_OUTPUT_PATH: ${EXECUTABLE_OUTPUT_PATH}") # option defaults # XXX CHANGE: Logging is enabled now by default, @@ -85,6 +89,7 @@ option(ENABLE_SHARED "Should libsrt be built as a shared library" ON) option(ENABLE_STATIC "Should libsrt be built as a static library" ON) option(ENABLE_SUFLIP "Should suflip tool be built" OFF) option(ENABLE_GETNAMEINFO "In-logs sockaddr-to-string should do rev-dns" OFF) +option(ENABLE_UNITTESTS "Enable unit tests" ON) option(USE_GNUTLS "Should use gnutls instead of openssl" OFF) option(ENABLE_CXX_DEPS "Extra library dependencies in srt.pc for the CXX libraries useful with C language" ON) option(USE_STATIC_LIBSTDCXX "Should use static rather than shared libstdc++" OFF) @@ -296,6 +301,7 @@ set (SRT_SRC_HAICRYPT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/haicrypt) set (SRT_SRC_SRTCORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/srtcore) set (SRT_SRC_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) set (SRT_SRC_TOOLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools) +set (SRT_SRC_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) if(WIN32) message(STATUS "DETECTED SYSTEM: WINDOWS; WIN32=1; PTW32_STATIC_LIB=1") @@ -370,7 +376,7 @@ elseif (WIN32 AND NOT MINGW) message(FATAL_ERROR "Failed to find pthread.h. Specify PTHREAD_INCLUDE_DIR.") endif() - find_library(PTHREAD_LIBRARY NAMES pthread pthread_dll pthread_lib HINTS C:/pthread-win32/lib) + find_library(PTHREAD_LIBRARY NAMES pthread pthread_dll pthread_lib HINTS C:/pthread-win32/lib C:/pthread-win64/lib) if (PTHREAD_LIBRARY) message(STATUS "Pthread library: ${PTHREAD_LIBRARY}") else() @@ -798,6 +804,37 @@ if (ENABLE_EXAMPLES) endif() + +if (ENABLE_UNITTESTS) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + include(googletest) + fetch_googletest( + ${PROJECT_SOURCE_DIR}/scripts + ${PROJECT_BINARY_DIR}/googletest + ) + + srt_add_program(test_srt test/test_buffer.cpp test/test_connection_timeout.cpp) + srt_make_application(test_srt) + + target_link_libraries( + test_srt + gtest_main + ${srt_link_library} + ${PTHREAD_LIBRARY} + ) + + add_test( + NAME + test_srt + COMMAND + ${CMAKE_BINARY_DIR}/test_srt + ) + + enable_testing() + +endif() + + install(PROGRAMS scripts/srt-ffplay DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/scripts/googletest-download.cmake b/scripts/googletest-download.cmake new file mode 100644 index 000000000..55f2c5a55 --- /dev/null +++ b/scripts/googletest-download.cmake @@ -0,0 +1,19 @@ +# code copied from https://crascit.com/2015/07/25/cmake-gtest/ +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) + +project(googletest-download NONE) + +include(ExternalProject) + +ExternalProject_Add( + googletest + SOURCE_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-src" + BINARY_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build" + GIT_REPOSITORY + https://github.com/google/googletest.git + GIT_TAG release-1.8.1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/scripts/googletest.cmake b/scripts/googletest.cmake new file mode 100644 index 000000000..57e5c937a --- /dev/null +++ b/scripts/googletest.cmake @@ -0,0 +1,32 @@ +# the following code to fetch googletest +# is inspired by and adapted after https://crascit.com/2015/07/25/cmake-gtest/ +# download and unpack googletest at configure time + +macro(fetch_googletest _download_module_path _download_root) + set(GOOGLETEST_DOWNLOAD_ROOT ${_download_root}) + configure_file( + ${_download_module_path}/googletest-download.cmake + ${_download_root}/CMakeLists.txt + @ONLY + ) + unset(GOOGLETEST_DOWNLOAD_ROOT) + + execute_process( + COMMAND + "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . + WORKING_DIRECTORY + ${_download_root} + ) + execute_process( + COMMAND + "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY + ${_download_root} + ) + + # adds the targers: gtest, gtest_main, gmock, gmock_main + add_subdirectory( + ${_download_root}/googletest-src + ${_download_root}/googletest-build + ) +endmacro() diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index 241db72d9..b09e55b48 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -902,11 +902,11 @@ void CRcvBuffer::ackData(int len) int bytes = 0; for (int i = m_iLastAckPos, n = (m_iLastAckPos + len) % m_iSize; i != n; i = (i + 1) % m_iSize) { - if (m_pUnit[i] != NULL) - { - pkts++; - bytes += m_pUnit[i]->m_Packet.getLength(); - } + if (m_pUnit[i] == NULL) + continue; + + pkts++; + bytes += m_pUnit[i]->m_Packet.getLength(); } if (pkts > 0) countBytes(pkts, bytes, true); } diff --git a/srtcore/buffer.h b/srtcore/buffer.h index 9284d707f..c13d0b446 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -382,9 +382,10 @@ class CRcvBuffer bool empty() const; private: - /// thread safe bytes counter + /// thread safe bytes counter of the Recv & Ack buffer + /// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true) /// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer. - // XXX Please document. + /// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer void countBytes(int pkts, int bytes, bool acked = false); diff --git a/test/test_buffer.cpp b/test/test_buffer.cpp new file mode 100644 index 000000000..b4af7cfb4 --- /dev/null +++ b/test/test_buffer.cpp @@ -0,0 +1,11 @@ +#include "gtest/gtest.h" +#include "buffer.h" + +TEST(CRcvBuffer, Create) +{ + const int buffer_size = 65536; + CUnitQueue unit_queue; + CRcvBuffer rcv_buffer(&unit_queue, buffer_size); + + EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size - 1); // logic +} diff --git a/test/test_connection_timeout.cpp b/test/test_connection_timeout.cpp new file mode 100644 index 000000000..ee6873c7f --- /dev/null +++ b/test/test_connection_timeout.cpp @@ -0,0 +1,74 @@ +#include + +#ifdef _WIN32 +#define _WINSOCKAPI_ // to include Winsock2.h instead of Winsock.h from windows.h +#include + +#if defined(__GNUC__) || defined(__MINGW32__) +extern "C" { + WINSOCK_API_LINKAGE INT WSAAPI inet_pton( INT Family, PCSTR pszAddrString, PVOID pAddrBuf); + WINSOCK_API_LINKAGE PCSTR WSAAPI inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize); +} +#endif + +#define INC__WIN_WINTIME // exclude gettimeofday from srt headers +#endif + +#include "srt.h" + + +TEST(SRT, ConnectionTimeoutTest) { + ASSERT_EQ(srt_startup(), 0); + + const int yes = 1; + const int no = 0; + + SRTSOCKET m_client_sock = srt_socket(AF_INET, SOCK_DGRAM, 0); + ASSERT_NE(m_client_sock, SRT_ERROR); + + ASSERT_NE(srt_setsockopt(m_client_sock, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // for async connect + ASSERT_NE(srt_setsockopt(m_client_sock, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // for async connect + ASSERT_NE(srt_setsockflag(m_client_sock, SRTO_SENDER, &yes, sizeof yes), SRT_ERROR); + ASSERT_NE(srt_setsockopt(m_client_sock, 0, SRTO_TSBPDMODE, &yes, sizeof yes), SRT_ERROR); + + const int pollid = srt_epoll_create(); + ASSERT_GE(pollid, 0); + const int epoll_out = SRT_EPOLL_OUT | SRT_EPOLL_ERR; + ASSERT_NE(srt_epoll_add_usock(pollid, m_client_sock, &epoll_out), SRT_ERROR); + + sockaddr_in sa; + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = htons(5555); + + ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1); + + sockaddr* psa = (sockaddr*)&sa; + + ASSERT_NE(srt_connect(m_client_sock, psa, sizeof sa), SRT_ERROR); + + + // Socket readiness for connection is checked by polling on WRITE allowed sockets. + + { + int rlen = 2; + SRTSOCKET read[2]; + + int wlen = 2; + SRTSOCKET write[2]; + + ASSERT_NE(srt_epoll_wait(pollid, read, &rlen, + write, &wlen, + -1, + 0, 0, 0, 0), SRT_ERROR); + + ASSERT_EQ(rlen, 1); + ASSERT_EQ(read[0], m_client_sock); + + } + + ASSERT_NE(srt_epoll_remove_usock(pollid, m_client_sock), SRT_ERROR); + ASSERT_NE(srt_close(m_client_sock), SRT_ERROR); + (void)srt_epoll_release(pollid); + (void)srt_cleanup(); +}