From ce7ac11eae8134736968d817a609b2b90358dcfa Mon Sep 17 00:00:00 2001 From: OSSRS-AI Date: Sun, 19 Oct 2025 14:30:25 -0400 Subject: [PATCH] AI: Add workflow test for HTTP conn --- trunk/configure | 2 +- trunk/src/app/srs_app_factory.cpp | 6 + trunk/src/app/srs_app_factory.hpp | 4 + trunk/src/app/srs_app_http_conn.cpp | 16 +- trunk/src/app/srs_app_http_conn.hpp | 2 + trunk/src/protocol/srs_protocol_http_conn.cpp | 8 + trunk/src/protocol/srs_protocol_http_conn.hpp | 14 +- trunk/src/utest/srs_utest_ai15.cpp | 23 -- trunk/src/utest/srs_utest_ai15.hpp | 16 - trunk/src/utest/srs_utest_ai16.cpp | 87 ----- trunk/src/utest/srs_utest_ai16.hpp | 51 --- trunk/src/utest/srs_utest_ai19.cpp | 188 +-------- trunk/src/utest/srs_utest_ai19.hpp | 70 ---- trunk/src/utest/srs_utest_http_conn.cpp | 162 ++++++++ trunk/src/utest/srs_utest_http_conn.hpp | 32 ++ trunk/src/utest/srs_utest_mock.cpp | 365 +++++++++++++++++- trunk/src/utest/srs_utest_mock.hpp | 164 +++++++- 17 files changed, 771 insertions(+), 439 deletions(-) create mode 100644 trunk/src/utest/srs_utest_http_conn.cpp create mode 100644 trunk/src/utest/srs_utest_http_conn.hpp diff --git a/trunk/configure b/trunk/configure index 887b07293..7a9f8c27a 100755 --- a/trunk/configure +++ b/trunk/configure @@ -382,7 +382,7 @@ if [[ $SRS_UTEST == YES ]]; then "srs_utest_source_lock" "srs_utest_stream_token" "srs_utest_rtc_recv_track" "srs_utest_st2" "srs_utest_hevc_structs" "srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_protocol3" "srs_utest_app" "srs_utest_mock" "srs_utest_rtc_playstream" "srs_utest_rtc_publishstream" - "srs_utest_rtc_conn" "srs_utest_rtmp_conn" "srs_utest_srt_conn") + "srs_utest_rtc_conn" "srs_utest_rtmp_conn" "srs_utest_srt_conn" "srs_utest_http_conn") MODULE_FILES+=("srs_utest_ai01" "srs_utest_ai02" "srs_utest_ai03" "srs_utest_ai04" "srs_utest_ai05" "srs_utest_ai06" "srs_utest_ai07" "srs_utest_ai08" "srs_utest_ai09" "srs_utest_ai10" "srs_utest_ai11" "srs_utest_ai12" "srs_utest_ai13" "srs_utest_ai14" "srs_utest_ai15" "srs_utest_ai16" "srs_utest_ai17" diff --git a/trunk/src/app/srs_app_factory.cpp b/trunk/src/app/srs_app_factory.cpp index db4e92619..d9023e34f 100644 --- a/trunk/src/app/srs_app_factory.cpp +++ b/trunk/src/app/srs_app_factory.cpp @@ -34,6 +34,7 @@ #include #include #include +#include ISrsAppFactory::ISrsAppFactory() { @@ -206,6 +207,11 @@ ISrsRtcPlayStream *SrsAppFactory::create_rtc_play_stream(ISrsExecRtcAsyncTask *e return new SrsRtcPlayStream(exec, expire, sender, cid); } +ISrsHttpResponseWriter *SrsAppFactory::create_http_response_writer(ISrsProtocolReadWriter *io) +{ + return new SrsHttpResponseWriter(io); +} + ISrsCoroutine *SrsAppFactory::create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid) { return kernel_factory_->create_coroutine(name, handler, cid); diff --git a/trunk/src/app/srs_app_factory.hpp b/trunk/src/app/srs_app_factory.hpp index 214adacb3..852a7c4bb 100644 --- a/trunk/src/app/srs_app_factory.hpp +++ b/trunk/src/app/srs_app_factory.hpp @@ -48,6 +48,8 @@ class ISrsRtcPacketReceiver; class ISrsExpire; class ISrsRtcPlayStream; class ISrsRtcPacketSender; +class ISrsHttpResponseWriter; +class ISrsProtocolReadWriter; // The factory to create app objects. class ISrsAppFactory : public ISrsKernelFactory @@ -90,6 +92,7 @@ public: virtual ISrsProtocolUtility *create_protocol_utility() = 0; virtual ISrsRtcPublishStream *create_rtc_publish_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid) = 0; virtual ISrsRtcPlayStream *create_rtc_play_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid) = 0; + virtual ISrsHttpResponseWriter *create_http_response_writer(ISrsProtocolReadWriter *io) = 0; }; // The factory to create app objects. @@ -137,6 +140,7 @@ public: virtual ISrsProtocolUtility *create_protocol_utility(); virtual ISrsRtcPublishStream *create_rtc_publish_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid); virtual ISrsRtcPlayStream *create_rtc_play_stream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid); + virtual ISrsHttpResponseWriter *create_http_response_writer(ISrsProtocolReadWriter *io); public: virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid); diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 84cbc67b1..5d83add9a 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -40,6 +40,7 @@ using namespace std; #include #include #include +#include ISrsHttpConnOwner::ISrsHttpConnOwner() { @@ -75,6 +76,7 @@ SrsHttpConn::SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd, trd_ = new SrsSTCoroutine("http", this, _srs_context->get_id()); config_ = _srs_config; + app_factory_ = _srs_app_factory; } SrsHttpConn::~SrsHttpConn() @@ -89,6 +91,7 @@ SrsHttpConn::~SrsHttpConn() srs_freep(delta_); config_ = NULL; + app_factory_ = NULL; } std::string SrsHttpConn::desc() @@ -199,8 +202,11 @@ srs_error_t SrsHttpConn::process_requests(ISrsRequest **preq) srs_assert(req_raw); SrsUniquePtr req(req_raw); + // It must be a owner setter interface. + ISrsHttpMessageOwnerSetter *hreq = dynamic_cast(req.get()); + srs_assert(hreq); + // Attach owner connection to message. - SrsHttpMessage *hreq = (SrsHttpMessage *)req.get(); hreq->set_connection(this); // copy request to last request object. @@ -208,18 +214,18 @@ srs_error_t SrsHttpConn::process_requests(ISrsRequest **preq) *preq = hreq->to_request(hreq->host()); // may should discard the body. - SrsHttpResponseWriter writer(skt_); - if ((err = handler_->on_http_message(req.get(), &writer)) != srs_success) { + SrsUniquePtr writer(app_factory_->create_http_response_writer(skt_)); + if ((err = handler_->on_http_message(req.get(), writer.get())) != srs_success) { return srs_error_wrap(err, "on http message"); } // ok, handle http request. - if ((err = process_request(&writer, req.get(), req_id)) != srs_success) { + if ((err = process_request(writer.get(), req.get(), req_id)) != srs_success) { return srs_error_wrap(err, "process request=%d", req_id); } // After the request is processed. - if ((err = handler_->on_message_done(req.get(), &writer)) != srs_success) { + if ((err = handler_->on_message_done(req.get(), writer.get())) != srs_success) { return srs_error_wrap(err, "on message done"); } diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 4d606333d..8699c961c 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -49,6 +49,7 @@ class ISrsSslConnection; class ISrsHttpConn; class ISrsAppConfig; class ISrsStatistic; +class ISrsAppFactory; // The owner of HTTP connection. class ISrsHttpConnOwner @@ -98,6 +99,7 @@ class SrsHttpConn : public ISrsHttpConn // clang-format off SRS_DECLARE_PRIVATE: // clang-format on ISrsAppConfig *config_; + ISrsAppFactory *app_factory_; // clang-format off SRS_DECLARE_PROTECTED: // clang-format on diff --git a/trunk/src/protocol/srs_protocol_http_conn.cpp b/trunk/src/protocol/srs_protocol_http_conn.cpp index 4ee883229..ea112430b 100644 --- a/trunk/src/protocol/srs_protocol_http_conn.cpp +++ b/trunk/src/protocol/srs_protocol_http_conn.cpp @@ -301,6 +301,14 @@ int SrsHttpParser::on_body(llhttp_t *parser, const char *at, size_t length) return 0; } +ISrsHttpMessageOwnerSetter::ISrsHttpMessageOwnerSetter() +{ +} + +ISrsHttpMessageOwnerSetter::~ISrsHttpMessageOwnerSetter() +{ +} + SrsHttpMessage::SrsHttpMessage(ISrsReader *reader, SrsFastStream *buffer) { owner_conn_ = NULL; diff --git a/trunk/src/protocol/srs_protocol_http_conn.hpp b/trunk/src/protocol/srs_protocol_http_conn.hpp index 2a2bfdb6a..b0e9d07cb 100644 --- a/trunk/src/protocol/srs_protocol_http_conn.hpp +++ b/trunk/src/protocol/srs_protocol_http_conn.hpp @@ -100,13 +100,25 @@ SRS_DECLARE_PRIVATE: // clang-format on static int on_body(llhttp_t *parser, const char *at, size_t length); }; +// The interface for setting the connection owner. +class ISrsHttpMessageOwnerSetter : public ISrsHttpMessage +{ +public: + ISrsHttpMessageOwnerSetter(); + virtual ~ISrsHttpMessageOwnerSetter(); + +public: + virtual void set_connection(ISrsConnection *conn) = 0; + virtual ISrsRequest *to_request(std::string vhost) = 0; +}; + // A Request represents an HTTP request received by a server // or to be sent by a client. // // The field semantics differ slightly between client and server // usage. In addition to the notes on the fields below, see the // documentation for Request.Write and RoundTripper. -class SrsHttpMessage : public ISrsHttpMessage +class SrsHttpMessage : public ISrsHttpMessageOwnerSetter { // clang-format off SRS_DECLARE_PRIVATE: // clang-format on diff --git a/trunk/src/utest/srs_utest_ai15.cpp b/trunk/src/utest/srs_utest_ai15.cpp index 28fb0efef..ec898f38f 100644 --- a/trunk/src/utest/srs_utest_ai15.cpp +++ b/trunk/src/utest/srs_utest_ai15.cpp @@ -230,29 +230,6 @@ VOID TEST(SrsServerTest, ListenRtmpSuccess) EXPECT_TRUE(server.get() != NULL); } -MockHttpServeMux::MockHttpServeMux() -{ - handle_count_ = 0; -} - -MockHttpServeMux::~MockHttpServeMux() -{ -} - -srs_error_t MockHttpServeMux::handle(std::string pattern, ISrsHttpHandler *handler) -{ - handle_count_++; - patterns_.push_back(pattern); - // Free the handler since we're not actually using it - srs_freep(handler); - return srs_success; -} - -srs_error_t MockHttpServeMux::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r) -{ - return srs_success; -} - // Test SrsServer::http_handle() method to verify proper HTTP API handler registration. // This test covers the major use scenario of registering all HTTP API endpoints including // root API, versioning, summaries, rusages, stats, meminfos, authors, features, vhosts, diff --git a/trunk/src/utest/srs_utest_ai15.hpp b/trunk/src/utest/srs_utest_ai15.hpp index 835cfe9c6..b450c5940 100644 --- a/trunk/src/utest/srs_utest_ai15.hpp +++ b/trunk/src/utest/srs_utest_ai15.hpp @@ -69,22 +69,6 @@ public: virtual std::string get_exporter_listen(); }; -// Mock ISrsCommonHttpHandler for testing SrsServer::http_handle() -class MockHttpServeMux : public ISrsCommonHttpHandler -{ -public: - int handle_count_; - std::vector patterns_; - -public: - MockHttpServeMux(); - virtual ~MockHttpServeMux(); - -public: - virtual srs_error_t handle(std::string pattern, ISrsHttpHandler *handler); - virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r); -}; - // Mock ISrsLog for testing SrsServer::on_signal() class MockLogForSignal : public ISrsLog { diff --git a/trunk/src/utest/srs_utest_ai16.cpp b/trunk/src/utest/srs_utest_ai16.cpp index a3543e58a..4cd532c70 100644 --- a/trunk/src/utest/srs_utest_ai16.cpp +++ b/trunk/src/utest/srs_utest_ai16.cpp @@ -776,93 +776,6 @@ VOID TEST(BufferWriterTest, WriteToHttpResponse) buffer_writer->close(); } -// Old mock implementations for backward compatibility -MockHttpxConn::MockHttpxConn() -{ - enable_stat_ = false; -} - -MockHttpxConn::~MockHttpxConn() -{ -} - -void MockHttpxConn::set_enable_stat(bool v) -{ - enable_stat_ = v; -} - -srs_error_t MockHttpxConn::on_start() -{ - return srs_success; -} - -srs_error_t MockHttpxConn::on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) -{ - return srs_success; -} - -srs_error_t MockHttpxConn::on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) -{ - return srs_success; -} - -srs_error_t MockHttpxConn::on_conn_done(srs_error_t r0) -{ - return r0; -} - -MockHttpConn::MockHttpConn() -{ - handler_ = new MockHttpxConn(); - remote_ip_ = "127.0.0.1"; -} - -MockHttpConn::~MockHttpConn() -{ - srs_freep(handler_); -} - -std::string MockHttpConn::remote_ip() -{ - return remote_ip_; -} - -const SrsContextId &MockHttpConn::get_id() -{ - static SrsContextId id; - return id; -} - -std::string MockHttpConn::desc() -{ - return "MockHttpConn"; -} - -void MockHttpConn::expire() -{ -} - -ISrsHttpConnOwner *MockHttpConn::handler() -{ - return handler_; -} - -MockHttpMessage::MockHttpMessage() : SrsHttpMessage() -{ - mock_conn_ = new MockHttpConn(); - set_connection(mock_conn_); -} - -MockHttpMessage::~MockHttpMessage() -{ - srs_freep(mock_conn_); -} - -std::string MockHttpMessage::path() -{ - return "/live/stream.flv"; -} - // New mock implementations for SrsLiveStream testing MockHttpxConnForLiveStream::MockHttpxConnForLiveStream() : SrsHttpxConn(NULL, NULL, NULL, "127.0.0.1", 1935, "", "") { diff --git a/trunk/src/utest/srs_utest_ai16.hpp b/trunk/src/utest/srs_utest_ai16.hpp index 6ab3a6711..d07e45d9e 100644 --- a/trunk/src/utest/srs_utest_ai16.hpp +++ b/trunk/src/utest/srs_utest_ai16.hpp @@ -52,57 +52,6 @@ public: virtual srs_error_t update_auth(ISrsRequest *r); }; -// Mock SrsHttpxConn for testing SrsLiveStream (old version for backward compatibility) -class MockHttpxConn : public ISrsHttpConnOwner -{ -public: - bool enable_stat_; - -public: - MockHttpxConn(); - virtual ~MockHttpxConn(); - -public: - virtual void set_enable_stat(bool v); - virtual srs_error_t on_start(); - virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); - virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); - virtual srs_error_t on_conn_done(srs_error_t r0); -}; - -// Mock SrsHttpConn for testing SrsLiveStream (old version for backward compatibility) -class MockHttpConn : public ISrsConnection, public ISrsExpire -{ -public: - MockHttpxConn *handler_; - std::string remote_ip_; - -public: - MockHttpConn(); - virtual ~MockHttpConn(); - -public: - virtual std::string remote_ip(); - virtual const SrsContextId &get_id(); - virtual std::string desc(); - virtual void expire(); - virtual ISrsHttpConnOwner *handler(); -}; - -// Mock SrsHttpMessage for testing SrsLiveStream (old version for backward compatibility) -class MockHttpMessage : public SrsHttpMessage -{ -public: - MockHttpConn *mock_conn_; - -public: - MockHttpMessage(); - virtual ~MockHttpMessage(); - -public: - virtual std::string path(); -}; - // Mock SrsHttpxConn for testing SrsLiveStream - inherits from real SrsHttpxConn class MockHttpxConnForLiveStream : public SrsHttpxConn { diff --git a/trunk/src/utest/srs_utest_ai19.cpp b/trunk/src/utest/srs_utest_ai19.cpp index b52c3412a..e7ea70360 100644 --- a/trunk/src/utest/srs_utest_ai19.cpp +++ b/trunk/src/utest/srs_utest_ai19.cpp @@ -1434,185 +1434,6 @@ VOID TEST(AppCasterFlvTest, ResourceManagerDelegation) srs_freep(real_manager); } -// Mock ISrsHttpConnOwner implementation for testing SrsHttpConn::cycle() -MockHttpConnOwnerForCycle::MockHttpConnOwnerForCycle() -{ - on_start_called_ = false; - on_http_message_called_ = false; - on_message_done_called_ = false; - on_conn_done_called_ = false; - on_start_error_ = srs_success; - on_http_message_error_ = srs_success; - on_message_done_error_ = srs_success; - on_conn_done_error_ = srs_success; -} - -MockHttpConnOwnerForCycle::~MockHttpConnOwnerForCycle() -{ - srs_freep(on_start_error_); - srs_freep(on_http_message_error_); - srs_freep(on_message_done_error_); - srs_freep(on_conn_done_error_); -} - -srs_error_t MockHttpConnOwnerForCycle::on_start() -{ - on_start_called_ = true; - if (on_start_error_ != srs_success) { - return srs_error_copy(on_start_error_); - } - return srs_success; -} - -srs_error_t MockHttpConnOwnerForCycle::on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) -{ - on_http_message_called_ = true; - if (on_http_message_error_ != srs_success) { - return srs_error_copy(on_http_message_error_); - } - return srs_success; -} - -srs_error_t MockHttpConnOwnerForCycle::on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) -{ - on_message_done_called_ = true; - if (on_message_done_error_ != srs_success) { - return srs_error_copy(on_message_done_error_); - } - return srs_success; -} - -srs_error_t MockHttpConnOwnerForCycle::on_conn_done(srs_error_t r0) -{ - on_conn_done_called_ = true; - if (on_conn_done_error_ != srs_success) { - srs_freep(r0); - return srs_error_copy(on_conn_done_error_); - } - return r0; -} - -void MockHttpConnOwnerForCycle::reset() -{ - on_start_called_ = false; - on_http_message_called_ = false; - on_message_done_called_ = false; - on_conn_done_called_ = false; - srs_freep(on_start_error_); - srs_freep(on_http_message_error_); - srs_freep(on_message_done_error_); - srs_freep(on_conn_done_error_); -} - -// Mock ISrsHttpParser implementation for testing SrsHttpConn::cycle() -MockHttpParserForCycle::MockHttpParserForCycle() -{ - initialize_called_ = false; - parse_message_called_ = false; - initialize_error_ = srs_success; - parse_message_error_ = srs_success; - mock_message_ = NULL; -} - -MockHttpParserForCycle::~MockHttpParserForCycle() -{ - srs_freep(initialize_error_); - srs_freep(parse_message_error_); -} - -srs_error_t MockHttpParserForCycle::initialize(enum llhttp_type type) -{ - initialize_called_ = true; - if (initialize_error_ != srs_success) { - return srs_error_copy(initialize_error_); - } - return srs_success; -} - -void MockHttpParserForCycle::set_jsonp(bool allow_jsonp) -{ -} - -srs_error_t MockHttpParserForCycle::parse_message(ISrsReader *reader, ISrsHttpMessage **ppmsg) -{ - parse_message_called_ = true; - if (parse_message_error_ != srs_success) { - return srs_error_copy(parse_message_error_); - } - *ppmsg = mock_message_; - return srs_success; -} - -void MockHttpParserForCycle::reset() -{ - initialize_called_ = false; - parse_message_called_ = false; - srs_freep(initialize_error_); - srs_freep(parse_message_error_); - mock_message_ = NULL; -} - -// Mock ISrsProtocolReadWriter implementation for testing SrsHttpConn::cycle() -MockProtocolReadWriterForCycle::MockProtocolReadWriterForCycle() -{ - recv_timeout_ = SRS_UTIME_NO_TIMEOUT; - send_timeout_ = SRS_UTIME_NO_TIMEOUT; -} - -MockProtocolReadWriterForCycle::~MockProtocolReadWriterForCycle() -{ -} - -srs_error_t MockProtocolReadWriterForCycle::read_fully(void *buf, size_t size, ssize_t *nread) -{ - return srs_success; -} - -srs_error_t MockProtocolReadWriterForCycle::read(void *buf, size_t size, ssize_t *nread) -{ - return srs_success; -} - -void MockProtocolReadWriterForCycle::set_recv_timeout(srs_utime_t tm) -{ - recv_timeout_ = tm; -} - -srs_utime_t MockProtocolReadWriterForCycle::get_recv_timeout() -{ - return recv_timeout_; -} - -int64_t MockProtocolReadWriterForCycle::get_recv_bytes() -{ - return 0; -} - -srs_error_t MockProtocolReadWriterForCycle::write(void *buf, size_t size, ssize_t *nwrite) -{ - return srs_success; -} - -void MockProtocolReadWriterForCycle::set_send_timeout(srs_utime_t tm) -{ - send_timeout_ = tm; -} - -srs_utime_t MockProtocolReadWriterForCycle::get_send_timeout() -{ - return send_timeout_; -} - -int64_t MockProtocolReadWriterForCycle::get_send_bytes() -{ - return 0; -} - -srs_error_t MockProtocolReadWriterForCycle::writev(const iovec *iov, int iov_size, ssize_t *nwrite) -{ - return srs_success; -} - // Mock ISrsCoroutine implementation for testing SrsHttpConn::cycle() MockCoroutineForCycle::MockCoroutineForCycle() { @@ -1699,15 +1520,15 @@ VOID TEST(HttpConnTest, CycleSuccessWithSingleRequest) srs_error_t err; // Create mock dependencies - MockHttpConnOwnerForCycle *mock_handler = new MockHttpConnOwnerForCycle(); - MockProtocolReadWriterForCycle *mock_skt = new MockProtocolReadWriterForCycle(); + MockHttpxConn *mock_handler = new MockHttpxConn(); + MockProtocolReadWriter *mock_skt = new MockProtocolReadWriter(); SrsHttpServeMux *mock_mux = new SrsHttpServeMux(); // Create SrsHttpConn SrsUniquePtr conn(new SrsHttpConn(mock_handler, mock_skt, mock_mux, "127.0.0.1", 8080)); // Create mock parser and coroutine - MockHttpParserForCycle *mock_parser = new MockHttpParserForCycle(); + MockHttpParser *mock_parser = new MockHttpParser(); MockCoroutineForCycle *mock_trd = new MockCoroutineForCycle(); // Create mock message - will be freed by SrsHttpConn::process_requests() @@ -1717,7 +1538,8 @@ VOID TEST(HttpConnTest, CycleSuccessWithSingleRequest) mock_message->is_keep_alive_ = false; // Configure mock parser to return our mock message - mock_parser->mock_message_ = mock_message; + mock_parser->messages_.push_back(mock_message); + mock_parser->cond_->signal(); // Inject mock dependencies into SrsHttpConn conn->parser_ = mock_parser; diff --git a/trunk/src/utest/srs_utest_ai19.hpp b/trunk/src/utest/srs_utest_ai19.hpp index 50ee5e759..a05884ff4 100644 --- a/trunk/src/utest/srs_utest_ai19.hpp +++ b/trunk/src/utest/srs_utest_ai19.hpp @@ -478,76 +478,6 @@ public: virtual void expire(); }; -// Mock ISrsHttpConnOwner for testing SrsHttpConn::cycle() -class MockHttpConnOwnerForCycle : public ISrsHttpConnOwner -{ -public: - bool on_start_called_; - bool on_http_message_called_; - bool on_message_done_called_; - bool on_conn_done_called_; - srs_error_t on_start_error_; - srs_error_t on_http_message_error_; - srs_error_t on_message_done_error_; - srs_error_t on_conn_done_error_; - -public: - MockHttpConnOwnerForCycle(); - virtual ~MockHttpConnOwnerForCycle(); - -public: - virtual srs_error_t on_start(); - virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); - virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); - virtual srs_error_t on_conn_done(srs_error_t r0); - void reset(); -}; - -// Mock ISrsHttpParser for testing SrsHttpConn::cycle() -class MockHttpParserForCycle : public ISrsHttpParser -{ -public: - bool initialize_called_; - bool parse_message_called_; - srs_error_t initialize_error_; - srs_error_t parse_message_error_; - ISrsHttpMessage *mock_message_; - -public: - MockHttpParserForCycle(); - virtual ~MockHttpParserForCycle(); - -public: - virtual srs_error_t initialize(enum llhttp_type type); - virtual void set_jsonp(bool allow_jsonp); - virtual srs_error_t parse_message(ISrsReader *reader, ISrsHttpMessage **ppmsg); - void reset(); -}; - -// Mock ISrsProtocolReadWriter for testing SrsHttpConn::cycle() -class MockProtocolReadWriterForCycle : public ISrsProtocolReadWriter -{ -public: - srs_utime_t recv_timeout_; - srs_utime_t send_timeout_; - -public: - MockProtocolReadWriterForCycle(); - virtual ~MockProtocolReadWriterForCycle(); - -public: - virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); - virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); - virtual void set_recv_timeout(srs_utime_t tm); - virtual srs_utime_t get_recv_timeout(); - virtual int64_t get_recv_bytes(); - virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); - virtual void set_send_timeout(srs_utime_t tm); - virtual srs_utime_t get_send_timeout(); - virtual int64_t get_send_bytes(); - virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); -}; - // Mock ISrsCoroutine for testing SrsHttpConn::cycle() class MockCoroutineForCycle : public ISrsCoroutine { diff --git a/trunk/src/utest/srs_utest_http_conn.cpp b/trunk/src/utest/srs_utest_http_conn.cpp new file mode 100644 index 000000000..6ca1967ac --- /dev/null +++ b/trunk/src/utest/srs_utest_http_conn.cpp @@ -0,0 +1,162 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This test is used to verify the basic workflow of the HTTP connection. +// It's finished with the help of AI, but each step is manually designed +// and verified. So this is not dominated by AI, but by humanbeing. +VOID TEST(HttpConnTest, ManuallyVerifyBasicWorkflowForHttpRequest) +{ + srs_error_t err; + + // Create mock objects for dependencies + SrsUniquePtr mock_config(new MockAppConfig()); + SrsUniquePtr mock_app_factory(new MockAppFactory()); + SrsUniquePtr mock_handler(new MockHttpxConn()); + MockProtocolReadWriter *mock_io = new MockProtocolReadWriter(); + MockHttpParser *mock_parser = new MockHttpParser(); + SrsUniquePtr mock_http_mux(new MockHttpServeMux()); + + // Setup mock config + mock_config->default_vhost_ = new SrsConfDirective(); + mock_config->default_vhost_->name_ = "vhost"; + mock_config->default_vhost_->args_.push_back("__defaultVhost__"); + + // Create SrsHttpConn - it takes ownership of mock_io + SrsUniquePtr conn(new SrsHttpConn(mock_handler.get(), mock_io, mock_http_mux.get(), "192.168.1.100", 8080)); + + // Inject mock dependencies into private fields + conn->config_ = mock_config.get(); + conn->app_factory_ = mock_app_factory.get(); + srs_freep(conn->parser_); + conn->parser_ = mock_parser; + + // Start the HTTP connection + HELPER_EXPECT_SUCCESS(conn->start()); + + // Wait for coroutine to start + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that http_mux->handle() was called + EXPECT_TRUE(mock_parser->initialize_called_); + EXPECT_TRUE(mock_handler->on_start_called_); + EXPECT_TRUE(mock_parser->parse_message_called_); + + // Create a mock HTTP message for the parser to return + // Note: The parser will take ownership of this message + MockHttpMessage *mock_message = new MockHttpMessage(); + mock_message->set_url("/api/v1/versions", false); + mock_parser->messages_.push_back(mock_message); + mock_parser->cond_->signal(); + + // Wait for message processing + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that http_mux->handle() and serve_http() were called + EXPECT_EQ(1, mock_http_mux->serve_http_count_); +} + +// This test is used to verify the basic workflow of the HTTPx connection. +// It's finished with the help of AI, but each step is manually designed +// and verified. So this is not dominated by AI, but by humanbeing. +VOID TEST(HttpConnTest, ManuallyVerifyBasicWorkflowForHttpxRequest) +{ + srs_error_t err; + + // Create mock objects for dependencies + SrsUniquePtr mock_config(new MockAppConfig()); + SrsUniquePtr mock_app_factory(new MockAppFactory()); + MockProtocolReadWriter *mock_io = new MockProtocolReadWriter(); + MockHttpParser *mock_parser = new MockHttpParser(); + SrsUniquePtr mock_http_mux(new MockHttpServeMux()); + MockSslConnection *mock_ssl = new MockSslConnection(); + + // Setup mock config + mock_config->default_vhost_ = new SrsConfDirective(); + mock_config->default_vhost_->name_ = "vhost"; + mock_config->default_vhost_->args_.push_back("__defaultVhost__"); + + // Create mock resource manager + SrsUniquePtr mock_manager(new MockConnectionManager()); + + // Create SrsHttpxConn - it takes ownership of mock_io + // Set key and cert to empty to disable SSL + SrsUniquePtr conn(new SrsHttpxConn(mock_manager.get(), mock_io, mock_http_mux.get(), "192.168.1.100", 8080, "", "")); + + // Inject mock dependencies into private fields + conn->config_ = mock_config.get(); + // Inject mock SSL connection + srs_freep(conn->ssl_); + conn->ssl_ = mock_ssl; + + // Access the internal SrsHttpConn through conn_ field (cast from ISrsHttpConn* to SrsHttpConn*) + SrsHttpConn *http_conn = new SrsHttpConn(conn.get(), mock_ssl, mock_http_mux.get(), "192.168.1.100", 8080); + http_conn->config_ = mock_config.get(); + http_conn->app_factory_ = mock_app_factory.get(); + srs_freep(http_conn->parser_); + http_conn->parser_ = mock_parser; + + // Inject the mock SrsHttpConn into conn_ field + srs_freep(conn->conn_); + conn->conn_ = http_conn; + + // Start the HTTPx connection + HELPER_EXPECT_SUCCESS(conn->start()); + + // Wait for coroutine to start + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that parser->initialize() was called + EXPECT_TRUE(mock_parser->initialize_called_); + EXPECT_TRUE(mock_parser->parse_message_called_); + + // Verify HTTPS handshake was called + EXPECT_TRUE(mock_ssl->handshake_called_); + + // Create a mock HTTP message for the parser to return + // Note: The parser will take ownership of this message + MockHttpMessage *mock_message = new MockHttpMessage(); + mock_message->set_url("/api/v1/versions", false); + mock_parser->messages_.push_back(mock_message); + mock_parser->cond_->signal(); + + // Wait for message processing + srs_usleep(1 * SRS_UTIME_MILLISECONDS); + + // Verify that http_mux->serve_http() was called + EXPECT_EQ(1, mock_http_mux->serve_http_count_); +} + diff --git a/trunk/src/utest/srs_utest_http_conn.hpp b/trunk/src/utest/srs_utest_http_conn.hpp new file mode 100644 index 000000000..50739699c --- /dev/null +++ b/trunk/src/utest/srs_utest_http_conn.hpp @@ -0,0 +1,32 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2025 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_HTTP_CONN_HPP +#define SRS_UTEST_HTTP_CONN_HPP + +/* +#include +*/ +#include + +#endif diff --git a/trunk/src/utest/srs_utest_mock.cpp b/trunk/src/utest/srs_utest_mock.cpp index 821ccd357..7d161ce22 100644 --- a/trunk/src/utest/srs_utest_mock.cpp +++ b/trunk/src/utest/srs_utest_mock.cpp @@ -1565,6 +1565,67 @@ void MockRtmpServer::reset() auto_response_value_ = true; } +// Mock ISrsProtocolReadWriter implementation for testing SrsHttpConn::cycle() +MockProtocolReadWriter::MockProtocolReadWriter() +{ + recv_timeout_ = SRS_UTIME_NO_TIMEOUT; + send_timeout_ = SRS_UTIME_NO_TIMEOUT; +} + +MockProtocolReadWriter::~MockProtocolReadWriter() +{ +} + +srs_error_t MockProtocolReadWriter::read_fully(void *buf, size_t size, ssize_t *nread) +{ + return srs_success; +} + +srs_error_t MockProtocolReadWriter::read(void *buf, size_t size, ssize_t *nread) +{ + return srs_success; +} + +void MockProtocolReadWriter::set_recv_timeout(srs_utime_t tm) +{ + recv_timeout_ = tm; +} + +srs_utime_t MockProtocolReadWriter::get_recv_timeout() +{ + return recv_timeout_; +} + +int64_t MockProtocolReadWriter::get_recv_bytes() +{ + return 0; +} + +srs_error_t MockProtocolReadWriter::write(void *buf, size_t size, ssize_t *nwrite) +{ + return srs_success; +} + +void MockProtocolReadWriter::set_send_timeout(srs_utime_t tm) +{ + send_timeout_ = tm; +} + +srs_utime_t MockProtocolReadWriter::get_send_timeout() +{ + return send_timeout_; +} + +int64_t MockProtocolReadWriter::get_send_bytes() +{ + return 0; +} + +srs_error_t MockProtocolReadWriter::writev(const iovec *iov, int iov_size, ssize_t *nwrite) +{ + return srs_success; +} + MockRtmpTransport::MockRtmpTransport() { } @@ -1585,7 +1646,7 @@ int MockRtmpTransport::osfd() ISrsProtocolReadWriter *MockRtmpTransport::io() { - return this; + return &mock_io_; } srs_error_t MockRtmpTransport::handshake() @@ -1656,6 +1717,90 @@ srs_error_t MockRtmpTransport::writev(const iovec *iov, int iov_size, ssize_t *n return srs_success; } +// Mock ISrsSslConnection implementation for testing HTTPS connections +MockSslConnection::MockSslConnection() +{ + handshake_called_ = false; + handshake_error_ = srs_success; + recv_timeout_ = SRS_UTIME_NO_TIMEOUT; + send_timeout_ = SRS_UTIME_NO_TIMEOUT; + recv_bytes_ = 0; + send_bytes_ = 0; +} + +MockSslConnection::~MockSslConnection() +{ + srs_freep(handshake_error_); +} + +srs_error_t MockSslConnection::handshake(std::string key_file, std::string crt_file) +{ + handshake_called_ = true; + return srs_error_copy(handshake_error_); +} + +void MockSslConnection::set_recv_timeout(srs_utime_t tm) +{ + recv_timeout_ = tm; +} + +srs_utime_t MockSslConnection::get_recv_timeout() +{ + return recv_timeout_; +} + +srs_error_t MockSslConnection::read_fully(void *buf, size_t size, ssize_t *nread) +{ + return srs_error_new(ERROR_NOT_SUPPORTED, "mock ssl read_fully"); +} + +int64_t MockSslConnection::get_recv_bytes() +{ + return recv_bytes_; +} + +int64_t MockSslConnection::get_send_bytes() +{ + return send_bytes_; +} + +srs_error_t MockSslConnection::read(void *buf, size_t size, ssize_t *nread) +{ + return srs_error_new(ERROR_NOT_SUPPORTED, "mock ssl read"); +} + +void MockSslConnection::set_send_timeout(srs_utime_t tm) +{ + send_timeout_ = tm; +} + +srs_utime_t MockSslConnection::get_send_timeout() +{ + return send_timeout_; +} + +srs_error_t MockSslConnection::write(void *buf, size_t size, ssize_t *nwrite) +{ + *nwrite = size; + send_bytes_ += size; + return srs_success; +} + +srs_error_t MockSslConnection::writev(const iovec *iov, int iov_size, ssize_t *nwrite) +{ + return srs_error_new(ERROR_NOT_SUPPORTED, "mock ssl writev"); +} + +void MockSslConnection::reset() +{ + handshake_called_ = false; + srs_freep(handshake_error_); + recv_timeout_ = SRS_UTIME_NO_TIMEOUT; + send_timeout_ = SRS_UTIME_NO_TIMEOUT; + recv_bytes_ = 0; + send_bytes_ = 0; +} + // Mock ISrsProtocolReadWriter implementation for SrsSrtRecvThread MockSrtConnection::MockSrtConnection() { @@ -1769,3 +1914,221 @@ srs_error_t MockSrtConnection::get_stats(SrsSrtStat &stat) { return srs_success; } + +// Mock ISrsHttpParser implementation for testing SrsHttpConn::cycle() +MockHttpParser::MockHttpParser() +{ + initialize_called_ = false; + parse_message_called_ = false; + initialize_error_ = srs_success; + parse_message_error_ = srs_success; + cond_ = new SrsCond(); +} + +MockHttpParser::~MockHttpParser() +{ + reset(); + srs_freep(cond_); +} + +srs_error_t MockHttpParser::initialize(enum llhttp_type type) +{ + initialize_called_ = true; + if (initialize_error_ != srs_success) { + return srs_error_copy(initialize_error_); + } + return srs_success; +} + +void MockHttpParser::set_jsonp(bool allow_jsonp) +{ +} + +srs_error_t MockHttpParser::parse_message(ISrsReader *reader, ISrsHttpMessage **ppmsg) +{ + parse_message_called_ = true; + + if (messages_.empty()) { + cond_->wait(); + } + + if (parse_message_error_ != srs_success) { + return srs_error_copy(parse_message_error_); + } + + if (messages_.empty()) { + return srs_error_new(ERROR_SOCKET_READ, "mock http parser no message"); + } + + ISrsHttpMessage *msg = messages_.front(); + messages_.erase(messages_.begin()); + *ppmsg = msg; + return srs_success; +} + +void MockHttpParser::reset() +{ + initialize_called_ = false; + parse_message_called_ = false; + srs_freep(initialize_error_); + srs_freep(parse_message_error_); + + for (vector::iterator it = messages_.begin(); it != messages_.end(); ++it) { + ISrsHttpMessage *msg = *it; + srs_freep(msg); + } + messages_.clear(); +} + +// Old mock implementations for backward compatibility +MockHttpxConn::MockHttpxConn() +{ + enable_stat_ = false; + on_start_called_ = false; + on_http_message_called_ = false; + on_message_done_called_ = false; + on_conn_done_called_ = false; + on_start_error_ = srs_success; + on_http_message_error_ = srs_success; + on_message_done_error_ = srs_success; + on_conn_done_error_ = srs_success; +} + +MockHttpxConn::~MockHttpxConn() +{ + srs_freep(on_start_error_); + srs_freep(on_http_message_error_); + srs_freep(on_message_done_error_); + srs_freep(on_conn_done_error_); +} + +void MockHttpxConn::set_enable_stat(bool v) +{ + enable_stat_ = v; +} + +srs_error_t MockHttpxConn::on_start() +{ + on_start_called_ = true; + if (on_start_error_ != srs_success) { + return srs_error_copy(on_start_error_); + } + return srs_success; +} + +srs_error_t MockHttpxConn::on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) +{ + on_http_message_called_ = true; + if (on_http_message_error_ != srs_success) { + return srs_error_copy(on_http_message_error_); + } + return srs_success; +} + +srs_error_t MockHttpxConn::on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) +{ + on_message_done_called_ = true; + if (on_message_done_error_ != srs_success) { + return srs_error_copy(on_message_done_error_); + } + return srs_success; +} + +srs_error_t MockHttpxConn::on_conn_done(srs_error_t r0) +{ + on_conn_done_called_ = true; + if (on_conn_done_error_ != srs_success) { + srs_freep(r0); + return srs_error_copy(on_conn_done_error_); + } + return r0; +} + +void MockHttpxConn::reset() +{ + on_start_called_ = false; + on_http_message_called_ = false; + on_message_done_called_ = false; + on_conn_done_called_ = false; + srs_freep(on_start_error_); + srs_freep(on_http_message_error_); + srs_freep(on_message_done_error_); + srs_freep(on_conn_done_error_); +} + +MockHttpConn::MockHttpConn() +{ + handler_ = new MockHttpxConn(); + remote_ip_ = "127.0.0.1"; +} + +MockHttpConn::~MockHttpConn() +{ + srs_freep(handler_); +} + +std::string MockHttpConn::remote_ip() +{ + return remote_ip_; +} + +const SrsContextId &MockHttpConn::get_id() +{ + static SrsContextId id; + return id; +} + +std::string MockHttpConn::desc() +{ + return "MockHttpConn"; +} + +void MockHttpConn::expire() +{ +} + +ISrsHttpConnOwner *MockHttpConn::handler() +{ + return handler_; +} + +MockHttpMessage::MockHttpMessage() : SrsHttpMessage() +{ + mock_conn_ = new MockHttpConn(); + set_connection(mock_conn_); +} + +MockHttpMessage::~MockHttpMessage() +{ + srs_freep(mock_conn_); +} + +std::string MockHttpMessage::path() +{ + return "/live/stream.flv"; +} + +MockHttpServeMux::MockHttpServeMux() +{ + handle_count_ = 0; + serve_http_count_ = 0; +} + +MockHttpServeMux::~MockHttpServeMux() +{ +} + +srs_error_t MockHttpServeMux::handle(std::string pattern, ISrsHttpHandler *handler) +{ + handle_count_++; + patterns_.push_back(pattern); + // Free the handler since we're not actually using it + srs_freep(handler); + return srs_success; +} + +srs_error_t MockHttpServeMux::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r) +{ + serve_http_count_++; + return srs_success; +} diff --git a/trunk/src/utest/srs_utest_mock.hpp b/trunk/src/utest/srs_utest_mock.hpp index 0b0af56d0..df73700e0 100644 --- a/trunk/src/utest/srs_utest_mock.hpp +++ b/trunk/src/utest/srs_utest_mock.hpp @@ -42,6 +42,8 @@ #include #include #include +#include +#include // Forward declarations class SrsRtcTrackDescription; @@ -769,8 +771,35 @@ public: void reset(); }; -class MockRtmpTransport : public ISrsRtmpTransport, public ISrsProtocolReadWriter +// Mock ISrsProtocolReadWriter for testing SrsHttpConn::cycle() +class MockProtocolReadWriter : public ISrsProtocolReadWriter { +public: + srs_utime_t recv_timeout_; + srs_utime_t send_timeout_; + +public: + MockProtocolReadWriter(); + virtual ~MockProtocolReadWriter(); + +public: + virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); + virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual int64_t get_recv_bytes(); + virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual int64_t get_send_bytes(); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); +}; + +class MockRtmpTransport : public ISrsRtmpTransport +{ +public: + MockProtocolReadWriter mock_io_; + public: MockRtmpTransport(); virtual ~MockRtmpTransport(); @@ -797,6 +826,36 @@ public: virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); }; +// Mock ISrsSslConnection for testing HTTPS connections +class MockSslConnection : public ISrsSslConnection +{ +public: + bool handshake_called_; + srs_error_t handshake_error_; + srs_utime_t recv_timeout_; + srs_utime_t send_timeout_; + int64_t recv_bytes_; + int64_t send_bytes_; + +public: + MockSslConnection(); + virtual ~MockSslConnection(); + +public: + virtual srs_error_t handshake(std::string key_file, std::string crt_file); + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); + void reset(); +}; + // Mock ISrsProtocolReadWriter for testing SrsSrtRecvThread class MockSrtConnection : public ISrsSrtConnection { @@ -837,4 +896,107 @@ public: virtual srs_error_t get_stats(SrsSrtStat &stat); }; +// Mock ISrsHttpParser for testing SrsHttpConn::cycle() +class MockHttpParser : public ISrsHttpParser +{ +public: + bool initialize_called_; + bool parse_message_called_; + srs_error_t initialize_error_; + srs_error_t parse_message_error_; + +public: + SrsCond *cond_; + std::vector messages_; + +public: + MockHttpParser(); + virtual ~MockHttpParser(); + +public: + virtual srs_error_t initialize(enum llhttp_type type); + virtual void set_jsonp(bool allow_jsonp); + virtual srs_error_t parse_message(ISrsReader *reader, ISrsHttpMessage **ppmsg); + void reset(); +}; + +// Mock SrsHttpxConn for testing SrsLiveStream (old version for backward compatibility) +class MockHttpxConn : public ISrsHttpConnOwner +{ +public: + bool enable_stat_; + +public: + bool on_start_called_; + bool on_http_message_called_; + bool on_message_done_called_; + bool on_conn_done_called_; + srs_error_t on_start_error_; + srs_error_t on_http_message_error_; + srs_error_t on_message_done_error_; + srs_error_t on_conn_done_error_; + +public: + MockHttpxConn(); + virtual ~MockHttpxConn(); + +public: + virtual void set_enable_stat(bool v); + virtual srs_error_t on_start(); + virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); + virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w); + virtual srs_error_t on_conn_done(srs_error_t r0); + void reset(); +}; + +// Mock SrsHttpConn for testing SrsLiveStream (old version for backward compatibility) +class MockHttpConn : public ISrsConnection, public ISrsExpire +{ +public: + MockHttpxConn *handler_; + std::string remote_ip_; + +public: + MockHttpConn(); + virtual ~MockHttpConn(); + +public: + virtual std::string remote_ip(); + virtual const SrsContextId &get_id(); + virtual std::string desc(); + virtual void expire(); + virtual ISrsHttpConnOwner *handler(); +}; + +// Mock SrsHttpMessage for testing SrsLiveStream (old version for backward compatibility) +class MockHttpMessage : public SrsHttpMessage +{ +public: + MockHttpConn *mock_conn_; + +public: + MockHttpMessage(); + virtual ~MockHttpMessage(); + +public: + virtual std::string path(); +}; + +// Mock ISrsCommonHttpHandler for testing SrsServer::http_handle() +class MockHttpServeMux : public ISrsCommonHttpHandler +{ +public: + int handle_count_; + int serve_http_count_; + std::vector patterns_; + +public: + MockHttpServeMux(); + virtual ~MockHttpServeMux(); + +public: + virtual srs_error_t handle(std::string pattern, ISrsHttpHandler *handler); + virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r); +}; + #endif