From a9a720e32f0b6d78a2fdaec01e8777f28fa1a01c Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 7 Apr 2019 12:59:37 +0800 Subject: [PATCH] Cover ST Coroutine and time unit. 3.0.48 --- README.md | 1 + trunk/auto/utest.sh | 2 +- trunk/configure | 2 +- trunk/src/app/srs_app_st.cpp | 11 +- trunk/src/core/srs_core.hpp | 2 +- trunk/src/kernel/srs_kernel_error.cpp | 8 +- trunk/src/service/srs_service_st.hpp | 13 ++ trunk/src/utest/srs_utest.cpp | 38 ++++++ trunk/src/utest/srs_utest_app.cpp | 169 ++++++++++++++++++++++++++ trunk/src/utest/srs_utest_app.hpp | 33 +++++ trunk/src/utest/srs_utest_service.cpp | 42 +++++++ trunk/src/utest/srs_utest_service.hpp | 33 +++++ 12 files changed, 345 insertions(+), 9 deletions(-) create mode 100644 trunk/src/utest/srs_utest_app.cpp create mode 100644 trunk/src/utest/srs_utest_app.hpp create mode 100644 trunk/src/utest/srs_utest_service.cpp create mode 100644 trunk/src/utest/srs_utest_service.hpp diff --git a/README.md b/README.md index 4e80a8a84..7e33eddd1 100755 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ Please select according to languages: ### V3 changes +* v3.0, 2019-04-07, Cover ST Coroutine and time unit. 3.0.48 * v3.0, 2019-04-06, Merge [#1304][bug #1304], Fix ST coroutine pull error. 3.0.47 * v3.0, 2019-04-05, Merge [#1339][bug #1339], Support HTTP-FLV params. 3.0.46 * v3.0, 2018-11-11, Merge [#1261][bug #1261], Support `_definst_` for Wowza. 3.0.44 diff --git a/trunk/auto/utest.sh b/trunk/auto/utest.sh index 903ea7b40..d658bf7f4 100755 --- a/trunk/auto/utest.sh +++ b/trunk/auto/utest.sh @@ -179,7 +179,7 @@ echo "" >> ${FILE}; echo "" >> ${FILE} # echo "# generate the utest binary" >> ${FILE} cat << END >> ${FILE} -${SRS_TRUNK_PREFIX}/${SRS_OBJS_DIR}/${APP_NAME} : \$(SRS_UTEST_DEPS) ${MODULE_OBJS} gtest_main.a +${SRS_TRUNK_PREFIX}/${SRS_OBJS_DIR}/${APP_NAME} : \$(SRS_UTEST_DEPS) ${MODULE_OBJS} gtest.a \$(CXX) -o \$@ \$(CPPFLAGS) \$(CXXFLAGS) \$^ \$(DEPS_LIBRARIES_FILES) ${LINK_OPTIONS} END diff --git a/trunk/configure b/trunk/configure index 6971c7654..a072789b6 100755 --- a/trunk/configure +++ b/trunk/configure @@ -315,7 +315,7 @@ fi if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" - "srs_utest_reload") + "srs_utest_reload" "srs_utest_service" "srs_utest_app") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index 7e36e4a67..243fae0ef 100755 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -110,7 +110,7 @@ srs_error_t SrsSTCoroutine::start() return err; } - if((trd = (srs_thread_t)st_thread_create(pfn, this, 1, 0)) == NULL){ + if ((trd = (srs_thread_t)st_thread_create(pfn, this, 1, 0)) == NULL) { err = srs_error_new(ERROR_ST_CREATE_CYCLE_THREAD, "create failed"); srs_freep(trd_err); @@ -126,7 +126,7 @@ srs_error_t SrsSTCoroutine::start() void SrsSTCoroutine::stop() { - if (!started || disposed) { + if (disposed) { return; } disposed = true; @@ -134,8 +134,11 @@ void SrsSTCoroutine::stop() interrupt(); void* res = NULL; - int r0 = st_thread_join((st_thread_t)trd, &res); - srs_assert(!r0); + // When not started, the rd is NULL. + if (trd) { + int r0 = st_thread_join((st_thread_t)trd, &res); + srs_assert(!r0); + } // Always override the error by the error from worker. srs_error_t err_res = (srs_error_t)res; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index fb9c0b6f7..d1fdd16ae 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -27,7 +27,7 @@ // current release version #define VERSION_MAJOR 3 #define VERSION_MINOR 0 -#define VERSION_REVISION 47 +#define VERSION_REVISION 48 // generated by configure, only macros. #include diff --git a/trunk/src/kernel/srs_kernel_error.cpp b/trunk/src/kernel/srs_kernel_error.cpp index 281f0b043..9ea9534de 100644 --- a/trunk/src/kernel/srs_kernel_error.cpp +++ b/trunk/src/kernel/srs_kernel_error.cpp @@ -83,9 +83,13 @@ std::string SrsCplxError::description() { while (next) { ss << "thread #" << next->cid << ": " << next->func << "() [" << next->file << ":" << next->line << "]" - << "[errno=" << next->rerrno << "]" - << endl; + << "[errno=" << next->rerrno << "]"; + next = next->wrapped; + + if (next) { + ss << endl; + } } desc = ss.str(); diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index aec303cfd..4a6998517 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -37,6 +37,19 @@ typedef void* srs_cond_t; typedef void* srs_mutex_t; typedef uint64_t srs_utime_t; +// The time unit in ms, for example 100 * SRS_UTIME_MILLISECONDS means 100ms. +#define SRS_UTIME_MILLISECONDS 1000 + +// The time unit in ms, for example 120 * SRS_UTIME_SECONDS means 120s. +#define SRS_UTIME_SECONDS 1000000 + +// The time unit in minutes, for example 3 * SRS_UTIME_MINUTES means 3m. +#define SRS_UTIME_MINUTES 60000000LL + +// The time unit in hours, for example 2 * SRS_UTIME_HOURS means 2h. +#define SRS_UTIME_HOURS 3600000000LL + +// Never timeout. #define SRS_UTIME_NO_TIMEOUT ((srs_utime_t) -1LL) // initialize st, requires epoll. diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index 7ba49dc40..9b0a0200e 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -36,6 +36,44 @@ ISrsThreadContext* _srs_context = new ISrsThreadContext(); SrsConfig* _srs_config = NULL; SrsServer* _srs_server = NULL; +// Disable coroutine test for OSX. +#if !defined(SRS_OSX) +#include +#endif + +// Initialize global settings. +srs_error_t prepare_main() { + srs_error_t err = srs_success; + + #if !defined(SRS_OSX) + if ((err = srs_st_init()) != srs_success) { + return srs_error_wrap(err, "init st"); + } + + srs_freep(_srs_context); + _srs_context = new SrsThreadContext(); + #endif + + return err; +} + +// 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) { + srs_error_t err = srs_success; + + if ((err = prepare_main()) != srs_success) { + fprintf(stderr, "Failed, %s\n", srs_error_desc(err).c_str()); + + int ret = srs_error_code(err); + srs_freep(err); + return ret; + } + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + MockEmptyLog::MockEmptyLog(SrsLogLevel l) { level = l; diff --git a/trunk/src/utest/srs_utest_app.cpp b/trunk/src/utest/srs_utest_app.cpp new file mode 100644 index 000000000..4a3388efd --- /dev/null +++ b/trunk/src/utest/srs_utest_app.cpp @@ -0,0 +1,169 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 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 + +using namespace std; + +#include + +// Disable coroutine test for OSX. +#if !defined(SRS_OSX) + +#include + +VOID TEST(AppCoroutineTest, Dummy) +{ + SrsDummyCoroutine dc; + + if (true) { + EXPECT_EQ(0, dc.cid()); + + srs_error_t err = dc.pull(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + + err = dc.start(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + } + + if (true) { + dc.stop(); + + EXPECT_EQ(0, dc.cid()); + + srs_error_t err = dc.pull(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + + err = dc.start(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + } + + if (true) { + dc.interrupt(); + + EXPECT_EQ(0, dc.cid()); + + srs_error_t err = dc.pull(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + + err = dc.start(); + EXPECT_TRUE(err != srs_success); + EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err)); + srs_freep(err); + } +} + +class MockCoroutineHandler : public ISrsCoroutineHandler { +public: + SrsSTCoroutine* trd; + srs_error_t err; + srs_cond_t running; +public: + MockCoroutineHandler() { + trd = NULL; + err = srs_success; + running = srs_cond_new(); + } + virtual ~MockCoroutineHandler() { + srs_cond_destroy(running); + } +public: + virtual srs_error_t cycle() { + srs_error_t r0 = srs_success; + + srs_cond_signal(running); + + while ((r0 = trd->pull()) == srs_success) { + if (err != srs_success) { + return err; + } + srs_usleep(10 * 1000); + } + + return r0; + } +}; + +VOID TEST(AppCoroutineTest, StartStop) +{ + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch); + ch.trd = ≻ + EXPECT_EQ(0, sc.cid()); + + // Thread stop after created. + sc.stop(); + + EXPECT_EQ(0, sc.cid()); + + srs_error_t err = sc.pull(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_TERMINATED == srs_error_code(err)); + srs_freep(err); + + // Should never reuse a disposed thread. + err = sc.start(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err)); + srs_freep(err); + } + + if (true) { + MockCoroutineHandler ch; + SrsSTCoroutine sc("test", &ch); + ch.trd = ≻ + EXPECT_EQ(0, sc.cid()); + + EXPECT_TRUE(srs_success == sc.start()); + EXPECT_TRUE(srs_success == sc.pull()); + + srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS); + EXPECT_TRUE(sc.cid() > 0); + + // Thread stop after started. + sc.stop(); + + srs_error_t err = sc.pull(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_INTERRUPED == srs_error_code(err)); + srs_freep(err); + + // Should never reuse a disposed thread. + err = sc.start(); + EXPECT_TRUE(srs_success != err); + EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err)); + srs_freep(err); + } +} + +#endif diff --git a/trunk/src/utest/srs_utest_app.hpp b/trunk/src/utest/srs_utest_app.hpp new file mode 100644 index 000000000..20c793c4c --- /dev/null +++ b/trunk/src/utest/srs_utest_app.hpp @@ -0,0 +1,33 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 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 SRS_UTEST_APP_HPP +#define SRS_UTEST_APP_HPP + +/* +#include +*/ +#include + +#endif + diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp new file mode 100644 index 000000000..343c21755 --- /dev/null +++ b/trunk/src/utest/srs_utest_service.cpp @@ -0,0 +1,42 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 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 + +using namespace std; + +#include + +// Disable coroutine test for OSX. +#if !defined(SRS_OSX) + +#include + +VOID TEST(ServiceTimeTest, TimeUnit) +{ + EXPECT_EQ(1000, SRS_UTIME_MILLISECONDS); + EXPECT_EQ(1000*1000, SRS_UTIME_SECONDS); + EXPECT_EQ(60*1000*1000, SRS_UTIME_MINUTES); + EXPECT_EQ(3600*1000*1000LL, SRS_UTIME_HOURS); +} + +#endif diff --git a/trunk/src/utest/srs_utest_service.hpp b/trunk/src/utest/srs_utest_service.hpp new file mode 100644 index 000000000..e6e2e2228 --- /dev/null +++ b/trunk/src/utest/srs_utest_service.hpp @@ -0,0 +1,33 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2019 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 SRS_UTEST_SERVICE_HPP +#define SRS_UTEST_SERVICE_HPP + +/* +#include +*/ +#include + +#endif +