// // Copyright (c) 2013-2025 The SRS Authors // // SPDX-License-Identifier: MIT // #include #include #include #include #include #include #include #include #include #include using namespace std; #include #include #include #include // Temporary disk config. std::string _srs_tmp_file_prefix = "/tmp/srs-utest-"; // Temporary network config. std::string _srs_tmp_host = "127.0.0.1"; int _srs_tmp_port = 11935; srs_utime_t _srs_tmp_timeout = (100 * SRS_UTIME_MILLISECONDS); // kernel module. ISrsLog *_srs_log = NULL; ISrsContext *_srs_context = NULL; // app module. SrsConfig *_srs_config = NULL; bool _srs_in_docker = false; bool _srs_config_by_env = false; // The binary name of SRS. const char *_srs_binary = NULL; #include static void srs_srt_utest_null_log_handler(void *opaque, int level, const char *file, int line, const char *area, const char *message) { // srt null log handler, do no print any log. } // Initialize global settings. srs_error_t prepare_main() { srs_error_t err = srs_success; if ((err = srs_global_initialize()) != srs_success) { return srs_error_wrap(err, "init global"); } _srs_server = new SrsServer(); srs_freep(_srs_log); _srs_log = new MockEmptyLog(SrsLogLevelError); if ((err = _srs_rtc_dtls_certificate->initialize()) != srs_success) { return srs_error_wrap(err, "rtc dtls certificate initialize"); } srs_freep(_srs_context); _srs_context = new SrsThreadContext(); if ((err = srs_srt_log_initialize()) != srs_success) { return srs_error_wrap(err, "srt log initialize"); } // Prevent the output of srt logs in utest. srt_setloghandler(NULL, srs_srt_utest_null_log_handler); _srt_eventloop = new SrsSrtEventLoop(); if ((err = _srt_eventloop->initialize()) != srs_success) { return srs_error_wrap(err, "srt poller initialize"); } if ((err = _srt_eventloop->start()) != srs_success) { return srs_error_wrap(err, "srt poller start"); } 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; _srs_binary = argv[0]; 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); int r0 = RUN_ALL_TESTS(); return r0; } MockEmptyLog::MockEmptyLog(SrsLogLevel l) { level_ = l; } MockEmptyLog::~MockEmptyLog() { } void srs_bytes_print(char *pa, int size) { for (int i = 0; i < size; i++) { char v = pa[i]; printf("%#x ", v); } printf("\n"); } // 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)); } VOID TEST(SampleTest, FastSampleMacrosTest) { EXPECT_TRUE(1); EXPECT_FALSE(0); EXPECT_EQ(1, 1); // == EXPECT_NE(1, 2); // != EXPECT_LE(1, 2); // <= EXPECT_LT(1, 2); // < EXPECT_GE(2, 1); // >= EXPECT_GT(2, 1); // > EXPECT_STREQ("winlin", "winlin"); EXPECT_STRNE("winlin", "srs"); EXPECT_STRCASEEQ("winlin", "Winlin"); EXPECT_STRCASENE("winlin", "srs"); EXPECT_FLOAT_EQ(1.0, 1.000000000000001); EXPECT_DOUBLE_EQ(1.0, 1.0000000000000001); EXPECT_NEAR(10, 15, 5); } VOID TEST(SampleTest, StringEQTest) { string str = "100"; EXPECT_TRUE("100" == str); EXPECT_EQ("100", str); EXPECT_STREQ("100", str.c_str()); } class MockSrsContextId { public: MockSrsContextId() { bind_ = NULL; } MockSrsContextId(const MockSrsContextId &cp) { bind_ = NULL; if (cp.bind_) { bind_ = cp.bind_->copy(); } } MockSrsContextId &operator=(const MockSrsContextId &cp) { srs_freep(bind_); if (cp.bind_) { bind_ = cp.bind_->copy(); } return *this; } virtual ~MockSrsContextId() { srs_freep(bind_); } public: MockSrsContextId *copy() const { MockSrsContextId *cp = new MockSrsContextId(); if (bind_) { cp->bind_ = bind_->copy(); } return cp; } private: MockSrsContextId *bind_; }; VOID TEST(SampleTest, ContextTest) { MockSrsContextId cid; cid.bind_ = new MockSrsContextId(); static std::map cache; cache[0] = cid; cache[0] = cid; } MockProtectedBuffer::MockProtectedBuffer() : raw_memory_(NULL), size_(0), data_(NULL) { } MockProtectedBuffer::~MockProtectedBuffer() { if (size_ && raw_memory_) { long page_size = sysconf(_SC_PAGESIZE); munmap(raw_memory_, page_size * 2); } } int MockProtectedBuffer::alloc(int size) { srs_assert(!raw_memory_); long page_size = sysconf(_SC_PAGESIZE); if (size >= page_size) return -1; char *data = (char *)mmap(NULL, page_size * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (data == MAP_FAILED) { return -1; } size_ = size; raw_memory_ = data; data_ = data + page_size - size; int r0 = mprotect(data + page_size, page_size, PROT_NONE); if (r0 < 0) { return r0; } return 0; } SrsCoroutineChan::SrsCoroutineChan() { lock_ = srs_mutex_new(); } SrsCoroutineChan::~SrsCoroutineChan() { srs_mutex_destroy(lock_); } SrsCoroutineChan &SrsCoroutineChan::push(void *value) { SrsLocker(&lock_); args_.push_back(value); return *this; } void *SrsCoroutineChan::pop() { SrsLocker(&lock_); void *arg = *args_.begin(); args_.erase(args_.begin()); return arg; } SrsCoroutineChan *SrsCoroutineChan::copy() { SrsLocker(&lock_); SrsCoroutineChan *cp = new SrsCoroutineChan(); cp->args_ = args_; return cp; }