Files
Sunshine/tests/unit/test_rtsp.cpp
T

102 lines
3.2 KiB
C++

/**
* @file tests/unit/test_rtsp.cpp
* @brief Verify RTSP response handlers through their common dispatcher signature.
*/
// standard includes
#include <array>
#include <string>
#include <utility>
// lib includes
#include <boost/asio.hpp>
extern "C" {
#include <moonlight-common-c/src/Rtsp.h>
}
// test includes
#include "../tests_common.h"
// local includes
#include <src/rtsp.h>
namespace rtsp_stream {
class rtsp_server_t;
/**
* @brief Release a parsed RTSP message and its allocation.
* @param message Message to release.
*/
void free_msg(PRTSP_MESSAGE message);
/**
* @brief Owning RTSP message type used by the dispatcher.
*/
using msg_t = util::safe_ptr<RTSP_MESSAGE, &free_msg>;
/**
* @brief Respond to OPTIONS through the common dispatcher signature.
* @param sock Connected client socket.
* @param session Launch session.
* @param req Request to handle.
*/
void cmd_option(rtsp_server_t *, boost::asio::ip::tcp::socket &sock, launch_session_t &session, msg_t &&req);
/**
* @brief Respond to DESCRIBE through the common dispatcher signature.
* @param sock Connected client socket.
* @param session Launch session.
* @param req Request to handle.
*/
void cmd_describe(rtsp_server_t *, boost::asio::ip::tcp::socket &sock, launch_session_t &session, msg_t &&req);
/**
* @brief Respond to PLAY through the common dispatcher signature.
* @param sock Connected client socket.
* @param session Launch session.
* @param req Request to handle.
*/
void cmd_play(rtsp_server_t *, boost::asio::ip::tcp::socket &sock, launch_session_t &session, msg_t &&req);
} // namespace rtsp_stream
/**
* @brief All three handlers respond with the request's sequence even without a server instance.
*/
TEST(RtspResponseTest, CommonDispatcherPreservesResponsesWithoutServerContext) {
using boost::asio::ip::tcp;
const std::array handlers {
&rtsp_stream::cmd_option,
&rtsp_stream::cmd_describe,
&rtsp_stream::cmd_play,
};
for (const auto handler : handlers) {
boost::asio::io_context io;
tcp::acceptor acceptor {io, {boost::asio::ip::address_v4::loopback(), 0}};
tcp::socket client {io};
client.connect(acceptor.local_endpoint());
auto server_socket = acceptor.accept();
rtsp_stream::launch_session_t session {};
rtsp_stream::msg_t request {new RTSP_MESSAGE {}};
request->sequenceNumber = 42;
handler(nullptr, server_socket, session, std::move(request));
server_socket.shutdown(tcp::socket::shutdown_send);
std::string response;
boost::system::error_code read_error;
boost::asio::read(client, boost::asio::dynamic_buffer(response), read_error);
ASSERT_EQ(read_error, boost::asio::error::eof);
EXPECT_TRUE(response.starts_with("RTSP/1.0 200 OK\r\n"));
EXPECT_NE(response.find("CSeq: 42\r\n"), std::string::npos);
if (handler == &rtsp_stream::cmd_describe) {
EXPECT_NE(response.find("a=x-ss-general.featureFlags:"), std::string::npos);
EXPECT_NE(response.find("a=x-ss-general.encryptionSupported:"), std::string::npos);
EXPECT_NE(response.find("a=fmtp:97 surround-params="), std::string::npos);
} else {
EXPECT_TRUE(response.ends_with("\r\n\r\n"));
}
}
}