From 0fd783e82b4735b4ef60698a60af1789daf98afa Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 3 Mar 2021 10:17:00 +0800 Subject: [PATCH] For #19, support utest and coverage by gtest. --- .circleci/config.yml | 24 +++++++++++++ .gitignore | 7 ++++ Makefile | 28 +++++++++++++++ README.md | 50 +++++++++++++++++++++++++-- auto/codecov.sh | 52 ++++++++++++++++++++++++++++ auto/coverage.sh | 39 +++++++++++++++++++++ utest/Makefile | 82 ++++++++++++++++++++++++++++++++++++++++++++ utest/st_utest.cpp | 49 ++++++++++++++++++++++++++ utest/st_utest.hpp | 36 +++++++++++++++++++ 9 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 .circleci/config.yml create mode 100755 auto/codecov.sh create mode 100755 auto/coverage.sh create mode 100644 utest/Makefile create mode 100644 utest/st_utest.cpp create mode 100644 utest/st_utest.hpp diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..a50dab1 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,24 @@ +version: 2 +jobs: + build: + docker: + - image: ossrs/srs:dev + steps: + - checkout + - run: | + make linux-debug + test: + docker: + - image: ossrs/srs:dev + steps: + - checkout + - run: | + ln -sf /usr/local/gtest utest/gtest && + make linux-debug-gcov && + ./obj/st_utest && bash auto/codecov.sh +workflows: + version: 2 + build_and_test: + jobs: + - build + - test diff --git a/.gitignore b/.gitignore index 2731a5b..e62491c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,10 @@ LINUX_*_DBG obj st.pc .idea + +gtest* +googletest-* +*.gcda +*.gcno +coverage +codecov diff --git a/Makefile b/Makefile index 71f96ba..f271b5b 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,9 @@ TARGETS = aix-debug aix-optimized \ solaris-debug solaris-optimized \ solaris-64-debug solaris-64-optimized +UTEST_TARGETS = darwin-debug-utest linux-debug-utest \ + darwin-debug-gcov linux-debug-gcov + # # Platform specifics # @@ -289,9 +292,14 @@ endif # or to enable stats for ST: # # make EXTRA_CFLAGS=-DDEBUG_STATS +# +# or enable the coverage for utest: +# make UTEST_FLAGS="-fprofile-arcs -ftest-coverage" +# ########################## CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS) +CFLAGS += $(UTEST_FLAGS) OBJS = $(TARGETDIR)/sched.o \ $(TARGETDIR)/stk.o \ @@ -351,6 +359,8 @@ unknown: @echo @for target in $(TARGETS); do echo $$target; done @echo + @for target in $(UTEST_TARGETS); do echo $$target; done + @echo st.pc: st.pc.in sed "s/@VERSION@/${VERSION}/g" < $< > $@ @@ -483,5 +493,23 @@ solaris-64-debug: solaris-64-optimized: $(MAKE) OS="SOLARIS_64" BUILD="OPT" +darwin-debug-utest: + @echo "Build utest for state-threads" + $(MAKE) OS="DARWIN" BUILD="DBG" + cd utest && $(MAKE) +linux-debug-utest: + @echo "Build utest for state-threads" + $(MAKE) OS="LINUX" BUILD="DBG" + cd utest && $(MAKE) + +darwin-debug-gcov: + @echo "Build utest with gcov for state-threads" + $(MAKE) OS="DARWIN" BUILD="DBG" UTEST_FLAGS="-fprofile-arcs -ftest-coverage" STATIC_ONLY=yes + cd utest && $(MAKE) UTEST_FLAGS="-fprofile-arcs -ftest-coverage" +linux-debug-gcov: + @echo "Build utest with gcov for state-threads" + $(MAKE) OS="LINUX" BUILD="DBG" UTEST_FLAGS="-fprofile-arcs -ftest-coverage" STATIC_ONLY=yes + cd utest && $(MAKE) UTEST_FLAGS="-fprofile-arcs -ftest-coverage" + ########################## diff --git a/README.md b/README.md index aa8ad70..0b63c51 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # state-threads ![](http://ossrs.net:8000/gif/v1/sls.gif?site=github.com&path=/srs/srsst) +[![](https://circleci.com/gh/ossrs/state-threads/tree/srs.svg?style=svg&circle-token=1ef1d5b5b0cde6c8c282ed856a18199f9e8f85a9)](https://circleci.com/gh/ossrs/state-threads/tree/srs) +[![](https://codecov.io/gh/ossrs/state-threads/branch/srs/graph/badge.svg)](https://codecov.io/gh/ossrs/state-threads/branch/srs) [![](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat) Fork from http://sourceforge.net/projects/state-threads, patched for [SRS](https://github.com/ossrs/srs/tree/2.0release). @@ -14,8 +16,8 @@ For original ST without any changes, checkout the [ST master branch](https://git Get code: ``` -git clone https://github.com/ossrs/state-threads.git st-1.9 && -git checkout -b srs origin/srs +git clone https://github.com/ossrs/state-threads.git && +cd state-threads && git checkout srs ``` For Linux: @@ -69,6 +71,7 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche - [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12). - [x] Refine performance for sleep or epoll_wait(0), [#17](https://github.com/ossrs/state-threads/issues/17). - [ ] Improve the performance of timer. [9fe8cfe5b](https://github.com/ossrs/state-threads/commit/9fe8cfe5b1c9741a2e671a46215184f267fba400), [7879c2b](https://github.com/ossrs/state-threads/commit/7879c2b), [387cddb](https://github.com/ossrs/state-threads/commit/387cddb) +- [x] Support utest by gtest and coverage by gcov/gocvr. ## GDB Tools @@ -88,6 +91,49 @@ Important cli options: 1. `--track-origins= [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem. 1. `--show-reachable= , --show-possibly-lost=`, to show the using memory. +## UTest and Coverage + +First of all, download [google test](https://github.com/google/googletest/releases/tag/release-1.6.0) to `utest/gtest`, check by: + +```bash +ls -lh utest/gtest/include/gtest/gtest.h >/dev/null && echo yes +``` + +To make ST with utest and run it: + +```bash +make linux-debug-gcov && ./obj/st_utest +``` + +> For macOS: `make darwin-debug-gcov && ./obj/st_utest` + +> Run utest without coverage: `make darwin-debug-utest && ./obj/st_utest` + +Then, install [gcovr](https://gcovr.com/en/stable/guide.html) for coverage: + +```bash +yum install -y python2-pip && +pip install lxml && pip install gcovr +``` + +> For macOS: `pip3 install gcovr` + +Finally, run test and get the report + +```bash +mkdir -p coverage && +gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html && +open coverage/st.html +``` + +> Note: We ignore `LINUX*` and `DARWIN*` which is `obj` actually. + +Or just run locally: + +```bash +bash auto/coverage.sh +``` + ## Docs & Analysis * Introduction: http://ossrs.github.io/state-threads/docs/st.html diff --git a/auto/codecov.sh b/auto/codecov.sh new file mode 100755 index 0000000..5f964b7 --- /dev/null +++ b/auto/codecov.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# In .circleci/config.yml, generate *.gcno with +# ./configure --gcov --without-research --without-librtmp && make +# and generate *.gcda by +# ./objs/srs_utest + +# Workdir is objs/cover. +workdir=`pwd`/codecov && rm -rf $workdir + +# Tool git is required to map the right path. +git --version >/dev/null 2>&1 +ret=$?; if [[ $ret -ne 0 ]]; then echo "Tool git is required, ret=$ret"; exit $ret; fi + +# Create trunk under workdir. +mkdir -p $workdir && cd $workdir +ret=$?; if [[ $ret -ne 0 ]]; then echo "Enter workdir failed, ret=$ret"; exit $ret; fi + +# Collect all *.gcno and *.gcda to objs/cover. +cd $workdir && for file in $(cd .. && ls *.c); do + cp ../$file $file && echo "Copy $file" && + if [[ -f ../obj/${file%.*}.gcno ]]; then + cp ../obj/${file%.*}.* . + fi +done +ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect *.gcno and *.gcda failed, ret=$ret"; exit $ret; fi + +# Generate *.gcov for coverage. +cd $workdir && +for file in $(ls *.c); do + gcov $file -o `dirname $file` + ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect $file failed, ret=$ret"; exit $ret; fi +done + +# Filter the gcov files, remove utest or gtest. +cd $workdir && +rm -f *gtest*.gcov *utest*.gcov +ret=$?; if [[ $ret -ne 0 ]]; then echo "Cook gcov files failed, ret=$ret"; exit $ret; fi + +# Upload report with *.gcov +# Remark: The file codecov.yml is not neccessary. It literally depends on git. +# Note: The right path is like: +# https://codecov.io/gh/ossrs/srs/src/3.0release/trunk/src/protocol/srs_rtmp_stack.cpp +# https://codecov.io/gh/ossrs/srs/src/20fbb4466fdc8ba5d810b8570df6004063212838/trunk/src/protocol/srs_rtmp_stack.cpp +# Remark: It takes a few minutes to sync with github, so it might not available when CircleCI is done. +# https://circleci.com/gh/ossrs/srs/tree/3.0release +# +# Note: Use '-X gcov' to avoid generate the gcov files again. +cd $workdir && +export CODECOV_TOKEN="0d616496-f781-4e7c-b285-d1f70a1cdf24" && +bash <(curl -s https://codecov.io/bash) -X gcov && +echo "Done" && exit 0 diff --git a/auto/coverage.sh b/auto/coverage.sh new file mode 100755 index 0000000..93f717c --- /dev/null +++ b/auto/coverage.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +if [[ ! -f utest/gtest/include/gtest/gtest.h ]]; then + ( + cd utest && rm -rf gtest && + curl https://github.com/google/googletest/archive/release-1.6.0.tar.gz -L -o googletest-release-1.6.0.tar.gz && + tar xf googletest-release-1.6.0.tar.gz && + ln -sf googletest-release-1.6.0 gtest && + echo "Setup gtest ok" + ) +fi +if [[ ! -f utest/gtest/include/gtest/gtest.h ]]; then + echo "No utest/gtest, please download from https://github.com/google/googletest/releases/tag/release-1.6.0" + exit -1 +else + echo "Check utest/gtest ok" +fi + +if [[ $(gcovr --version >/dev/null && echo yes) != yes ]]; then + echo "Please install gcovr: https://github.com/ossrs/state-threads/tree/srs#utest-and-coverage" + exit -1 +fi + +IS_LINUX=yes +uname -s|grep Darwin >/dev/null && IS_DARWIN=yes && IS_LINUX=no +echo "IS_LINUX: $IS_LINUX, IS_DARWIN: $IS_DARWIN" + +echo "Build and run utest" +if [[ $IS_DARWIN == yes ]]; then + make clean && make darwin-debug-gcov && ./obj/st_utest +else + make clean && make linux-debug-gcov && ./obj/st_utest +fi + +echo "Generating coverage" +mkdir -p coverage && +gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html && +echo "Coverage report at coverage/st.html" && +open coverage/st.html diff --git a/utest/Makefile b/utest/Makefile new file mode 100644 index 0000000..3fcb026 --- /dev/null +++ b/utest/Makefile @@ -0,0 +1,82 @@ +# user must run make the objs/utest dir +# at the same dir of Makefile. + +# A sample Makefile for building Google Test and using it in user +# tests. Please tweak it to suit your environment and project. You +# may want to move it to your project's root directory. +# +# SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +# Please tweak the following variable definitions as needed by your +# project, except GTEST_HEADERS, which you can use in your own targets +# but shouldn't modify. + +# Points to the root of Google Test, relative to where this file is. +# Remember to tweak this if you move this file. +GTEST_DIR = ./gtest + +# Flags passed to the preprocessor. +CPPFLAGS += -I$(GTEST_DIR)/include + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -O0 -std=c++11 +CXXFLAGS += -Wall -Wno-deprecated-declarations -Wno-unused-private-field -Wno-unused-command-line-argument +CXXFLAGS += -DGTEST_USE_OWN_TR1_TUPLE=1 + +# All tests produced by this Makefile. Remember to add new tests you +# created to the list. +TESTS = ../obj/st_utest + +# All Google Test headers. Usually you shouldn't change this +# definition. +GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \ + $(GTEST_DIR)/include/gtest/internal/*.h + +# House-keeping build targets. + +all : $(TESTS) + +clean : + rm -f $(TESTS) gtest.a gtest_main.a *.o *.gcno *.gcda + +# Usually you shouldn't tweak such internal variables, indicated by a +# trailing _. +GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) + +# For simplicity and to avoid depending on Google Test's +# implementation details, the dependencies specified below are +# conservative and not optimized. This is fine as Google Test +# compiles fast and for ordinary users its source rarely changes. +../obj/gtest-all.o : $(GTEST_SRCS_) + $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \ + $(GTEST_DIR)/src/gtest-all.cc -o $@ + +../obj/gtest.a : ../obj/gtest-all.o + $(AR) $(ARFLAGS) $@ $^ + +##################################################################################### +##################################################################################### +# ST(state-threads) utest section +##################################################################################### +##################################################################################### + +# Includes, the include dir. +ST_UTEST_INC = -I../obj -I./ + +# Depends, the depends objects +ST_UTEST_DEPS = ../obj/libst.a + +# Depends, utest header files +UTEST_DEPS = st_utest.hpp + +# Objects, build each object of utest +../obj/st_utest.o : st_utest.cpp $(ST_UTEST_DEPS) $(UTEST_DEPS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(UTEST_FLAGS) $(ST_UTEST_INC) -c st_utest.cpp -o $@ + +# generate the utest binary +../obj/st_utest : ../obj/st_utest.o ../obj/gtest.a $(ST_UTEST_DEPS) + $(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) $(UTEST_FLAGS) $^ -lpthread -ldl diff --git a/utest/st_utest.cpp b/utest/st_utest.cpp new file mode 100644 index 0000000..a31744b --- /dev/null +++ b/utest/st_utest.cpp @@ -0,0 +1,49 @@ +/* +The MIT License (MIT) + +Copyright (c) 2021 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include + +// We could do something in the main of utest. +// Copy from gtest-1.6.0/src/gtest_main.cc +GTEST_API_ int main(int argc, char **argv) { + // Select the best event system available on the OS. In Linux this is + // epoll(). On BSD it will be kqueue. + assert(st_set_eventsys(ST_EVENTSYS_ALT) != -1); + assert(st_init() == 0); + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +// basic test and samples. +VOID TEST(SampleTest, FastSampleInt64Test) +{ + EXPECT_EQ(1, (int)sizeof(int8_t)); + EXPECT_EQ(2, (int)sizeof(int16_t)); + EXPECT_EQ(4, (int)sizeof(int32_t)); + EXPECT_EQ(8, (int)sizeof(int64_t)); +} + diff --git a/utest/st_utest.hpp b/utest/st_utest.hpp new file mode 100644 index 0000000..a310bb0 --- /dev/null +++ b/utest/st_utest.hpp @@ -0,0 +1,36 @@ +/* +The MIT License (MIT) + +Copyright (c) 2021 Winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef ST_UTEST_PUBLIC_HPP +#define ST_UTEST_PUBLIC_HPP + +// Before define the private/protected, we must include some system header files. +// Or it may fail with: +// redeclared with different access struct __xfer_bufptrs +// @see https://stackoverflow.com/questions/47839718/sstream-redeclared-with-public-access-compiler-error +#include + +#define VOID + +#endif +