tests: Add initial unit tests
These tests are mostly just placeholders until something more substantial is added. They are good tests, but it would be better to also test the functions in different kinds of scenarios. Note: the Crypto++ is causing problems in tests on Windows, because the CMake is rerun often and this causes the Crypto++ linking to disappear.
This commit is contained in:
parent
ea55f655ea
commit
5fe0116327
|
@ -10,3 +10,4 @@ config
|
|||
doc
|
||||
build
|
||||
common
|
||||
tests
|
|
@ -9,7 +9,7 @@
|
|||
#include "debug.hh" // debug prints
|
||||
#include "frame.hh" // frame related functions
|
||||
#include "util.hh" // types
|
||||
#include "version.hh"
|
||||
#include "version.hh" // version
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
|
|
@ -7,7 +7,10 @@ add_executable(${PROJECT_NAME})
|
|||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
main.cpp
|
||||
TestGTest.cpp
|
||||
tests_encryption.cpp
|
||||
tests_rtcp.cpp
|
||||
tests_rtp.cpp
|
||||
tests_version.cpp
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#include "lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(DefaultTest, ctor) {
|
||||
EXPECT_STREQ("2.0.1", uvgrtp::get_version().c_str());
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
#include "lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
// network parameters of example
|
||||
constexpr char SENDER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char RECEIVER_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
constexpr auto EXAMPLE_DURATION = std::chrono::seconds(1);
|
||||
|
||||
// encryption parameters of example
|
||||
enum Key_length { SRTP_128 = 128, SRTP_196 = 196, SRTP_256 = 256 };
|
||||
constexpr Key_length KEY_SIZE = SRTP_256;
|
||||
constexpr int KEY_SIZE_BYTES = KEY_SIZE / 8;
|
||||
constexpr int SALT_SIZE = 112;
|
||||
constexpr int SALT_SIZE_BYTES = SALT_SIZE / 8;
|
||||
|
||||
void process_frame(uvgrtp::frame::rtp_frame* frame);
|
||||
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES]);
|
||||
|
||||
|
||||
std::unique_ptr<std::thread> user_initialization(uvgrtp::context& ctx, Key_length sha,
|
||||
uvgrtp::session* sender_session, uvgrtp::media_stream* send);
|
||||
|
||||
TEST(EncryptionTests, no_send_user) {
|
||||
uvgrtp::context ctx;
|
||||
|
||||
uvgrtp::session* sender_session = nullptr;
|
||||
uvgrtp::media_stream* send = nullptr;
|
||||
std::unique_ptr<std::thread> receiver;
|
||||
|
||||
receiver = user_initialization(ctx, SRTP_256, sender_session, send);
|
||||
|
||||
// All media is now encrypted/decrypted automatically
|
||||
char* message = (char*)"Hello, world!";
|
||||
size_t msg_len = strlen(message);
|
||||
|
||||
if (send)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
for (unsigned int i = 0; i < 10; ++i)
|
||||
{
|
||||
EXPECT_EQ(RTP_OK, send->push_frame((uint8_t*)message, msg_len, RTP_NO_FLAGS));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
sender_session->destroy_stream(send);
|
||||
|
||||
if (receiver && receiver->joinable())
|
||||
{
|
||||
receiver->join();
|
||||
}
|
||||
|
||||
if (sender_session)
|
||||
ctx.destroy_session(sender_session);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::thread> user_initialization(uvgrtp::context& ctx, Key_length sha,
|
||||
uvgrtp::session* sender_session, uvgrtp::media_stream* send)
|
||||
{
|
||||
uint8_t key[KEY_SIZE_BYTES] = { 0 };
|
||||
uint8_t salt[SALT_SIZE_BYTES] = { 0 };
|
||||
|
||||
// initialize SRTP key and salt with dummy values
|
||||
for (int i = 0; i < KEY_SIZE_BYTES; ++i)
|
||||
key[i] = i;
|
||||
|
||||
for (int i = 0; i < SALT_SIZE_BYTES; ++i)
|
||||
salt[i] = i * 2;
|
||||
|
||||
// Enable SRTP and let user manage the keys
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER | RCE_SRTP_KEYSIZE_256;
|
||||
|
||||
sender_session = ctx.create_session(RECEIVER_ADDRESS);
|
||||
send = sender_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_GENERIC, flags);
|
||||
|
||||
EXPECT_NE(nullptr, sender_session);
|
||||
EXPECT_NE(nullptr, send);
|
||||
if (send)
|
||||
send->add_srtp_ctx(key, salt); // add user context
|
||||
|
||||
return std::unique_ptr<std::thread>(new std::thread(receive_func, key, salt));
|
||||
}
|
||||
|
||||
void receive_func(uint8_t key[KEY_SIZE_BYTES], uint8_t salt[SALT_SIZE_BYTES])
|
||||
{
|
||||
/* See sending.cc for more details */
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session* receiver_session = ctx.create_session(SENDER_ADDRESS);
|
||||
EXPECT_NE(nullptr, receiver_session);
|
||||
|
||||
/* Enable SRTP and let user manage keys */
|
||||
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
|
||||
|
||||
flags |= RCE_SRTP_KEYSIZE_256;
|
||||
|
||||
/* See sending.cc for more details about create_stream() */
|
||||
uvgrtp::media_stream* recv = receiver_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
EXPECT_NE(nullptr, recv);
|
||||
|
||||
if (recv)
|
||||
{
|
||||
recv->add_srtp_ctx(key, salt);
|
||||
}
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
uvgrtp::frame::rtp_frame* frame = nullptr;
|
||||
|
||||
if (recv)
|
||||
{
|
||||
while (std::chrono::steady_clock::now() - start < EXAMPLE_DURATION)
|
||||
{
|
||||
frame = recv->pull_frame(10);
|
||||
if (frame)
|
||||
{
|
||||
process_frame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receiver_session->destroy_stream(recv);
|
||||
ctx.destroy_session(receiver_session);
|
||||
}
|
||||
|
||||
void process_frame(uvgrtp::frame::rtp_frame* frame)
|
||||
{
|
||||
std::string payload = std::string((char*)frame->payload, frame->payload_len);
|
||||
EXPECT_NE(0, frame->payload_len);
|
||||
|
||||
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
#include "lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
constexpr char LOCAL_INTERFACE[] = "127.0.0.1";
|
||||
constexpr uint16_t LOCAL_PORT = 8888;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8890;
|
||||
|
||||
constexpr uint16_t PAYLOAD_LEN = 256;
|
||||
constexpr uint16_t FRAME_RATE = 30;
|
||||
constexpr uint32_t EXAMPLE_RUN_TIME_S = 15;
|
||||
constexpr int SEND_TEST_PACKETS = FRAME_RATE * EXAMPLE_RUN_TIME_S;
|
||||
constexpr int PACKET_INTERVAL_MS = 1000 / FRAME_RATE;
|
||||
|
||||
void receiver_hook(uvgrtp::frame::rtcp_receiver_report* frame);
|
||||
void sender_hook(uvgrtp::frame::rtcp_sender_report* frame);
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session* local_session, uvgrtp::session* remote_session,
|
||||
uvgrtp::media_stream* send, uvgrtp::media_stream* receive);
|
||||
|
||||
|
||||
|
||||
TEST(RTCPTests, rtcp) {
|
||||
std::cout << "Starting uvgRTP RTCP hook example" << std::endl;
|
||||
|
||||
// Creation of RTP stream. See sending example for more details
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session* local_session = ctx.create_session(REMOTE_ADDRESS);
|
||||
EXPECT_NE(nullptr, local_session);
|
||||
|
||||
uvgrtp::session* remote_session = ctx.create_session(LOCAL_INTERFACE);
|
||||
EXPECT_NE(nullptr, remote_session);
|
||||
|
||||
int flags = RCE_RTCP;
|
||||
uvgrtp::media_stream* local_stream = local_session->create_stream(LOCAL_PORT, REMOTE_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
EXPECT_NE(nullptr, local_stream);
|
||||
|
||||
uvgrtp::media_stream* remote_stream = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT,
|
||||
RTP_FORMAT_GENERIC, flags);
|
||||
EXPECT_NE(nullptr, remote_stream);
|
||||
|
||||
|
||||
if (local_stream)
|
||||
{
|
||||
EXPECT_EQ(RTP_OK, local_stream->get_rtcp()->install_receiver_hook(receiver_hook));
|
||||
}
|
||||
|
||||
if (remote_stream)
|
||||
{
|
||||
EXPECT_EQ(RTP_OK, remote_stream->get_rtcp()->install_sender_hook(sender_hook));
|
||||
}
|
||||
|
||||
if (local_stream)
|
||||
{
|
||||
uint8_t buffer[PAYLOAD_LEN] = { 0 };
|
||||
memset(buffer, 'a', PAYLOAD_LEN);
|
||||
|
||||
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
|
||||
|
||||
for (unsigned int i = 0; i < SEND_TEST_PACKETS; ++i)
|
||||
{
|
||||
EXPECT_EQ(RTP_OK, local_stream->push_frame((uint8_t*)buffer, PAYLOAD_LEN, RTP_NO_FLAGS));
|
||||
|
||||
wait_until_next_frame(start, i);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void receiver_hook(uvgrtp::frame::rtcp_receiver_report* frame)
|
||||
{
|
||||
std::cout << "RTCP receiver report! ----------" << std::endl;
|
||||
|
||||
for (auto& block : frame->report_blocks)
|
||||
{
|
||||
std::cout << "ssrc: " << block.ssrc << std::endl;
|
||||
std::cout << "fraction: " << block.fraction << std::endl;
|
||||
std::cout << "lost: " << block.lost << std::endl;
|
||||
std::cout << "last_seq: " << block.last_seq << std::endl;
|
||||
std::cout << "jitter: " << block.jitter << std::endl;
|
||||
std::cout << "lsr: " << block.lsr << std::endl;
|
||||
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
/* RTCP frames can be deallocated using delete */
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void sender_hook(uvgrtp::frame::rtcp_sender_report* frame)
|
||||
{
|
||||
std::cout << "RTCP sender report! ----------" << std::endl;
|
||||
std::cout << "NTP msw: " << frame->sender_info.ntp_msw << std::endl;
|
||||
std::cout << "NTP lsw: " << frame->sender_info.ntp_lsw << std::endl;
|
||||
std::cout << "RTP timestamp: " << frame->sender_info.rtp_ts << std::endl;
|
||||
std::cout << "packet count: " << frame->sender_info.pkt_cnt << std::endl;
|
||||
std::cout << "byte count: " << frame->sender_info.byte_cnt << std::endl;
|
||||
|
||||
for (auto& block : frame->report_blocks)
|
||||
{
|
||||
std::cout << "ssrc: " << block.ssrc << std::endl;
|
||||
std::cout << "fraction: " << block.fraction << std::endl;
|
||||
std::cout << "lost: " << block.lost << std::endl;
|
||||
std::cout << "last_seq: " << block.last_seq << std::endl;
|
||||
std::cout << "jitter: " << block.jitter << std::endl;
|
||||
std::cout << "lsr: " << block.lsr << std::endl;
|
||||
std::cout << "dlsr (ms): " << uvgrtp::clock::jiffies_to_ms(block.dlsr)
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
/* RTCP frames can be deallocated using delete */
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void wait_until_next_frame(std::chrono::steady_clock::time_point& start, int frame_index)
|
||||
{
|
||||
// wait until it is time to send the next frame. Simulates a steady sending pace
|
||||
// and included only for demostration purposes since you can use uvgRTP to send
|
||||
// packets as fast as desired
|
||||
auto time_since_start = std::chrono::steady_clock::now() - start;
|
||||
auto next_frame_time = (frame_index + 1) * std::chrono::milliseconds(PACKET_INTERVAL_MS);
|
||||
if (next_frame_time > time_since_start)
|
||||
{
|
||||
std::this_thread::sleep_for(next_frame_time - time_since_start);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session* local_session, uvgrtp::session* remote_session,
|
||||
uvgrtp::media_stream* send, uvgrtp::media_stream* receive)
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
local_session->destroy_stream(send);
|
||||
}
|
||||
|
||||
if (receive)
|
||||
{
|
||||
remote_session->destroy_stream(receive);
|
||||
}
|
||||
|
||||
if (local_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(local_session);
|
||||
}
|
||||
|
||||
if (remote_session)
|
||||
{
|
||||
// Session must be destroyed manually
|
||||
ctx.destroy_session(remote_session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include "lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
// parameters for this test. You can change these to suit your network environment
|
||||
constexpr uint16_t LOCAL_PORT = 8890;
|
||||
|
||||
constexpr char REMOTE_ADDRESS[] = "127.0.0.1";
|
||||
constexpr uint16_t REMOTE_PORT = 8888;
|
||||
|
||||
void rtp_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame);
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session* sess, uvgrtp::media_stream* ms);
|
||||
void process_rtp_frame(uvgrtp::frame::rtp_frame* frame);
|
||||
|
||||
// TODO: 1) Test only sending, 2) test sending with different configuration, 3) test receiving with different configurations, and
|
||||
// 4) test sending and receiving within same test while checking frame size
|
||||
|
||||
|
||||
TEST(RTPTests, rtp_hook)
|
||||
{
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
|
||||
EXPECT_NE(nullptr, sess);
|
||||
|
||||
int flags = RTP_NO_FLAGS;
|
||||
uvgrtp::media_stream* receiver = sess->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_H265, flags);
|
||||
EXPECT_NE(nullptr, receiver);
|
||||
EXPECT_EQ(RTP_OK, receiver->install_receive_hook(nullptr, rtp_receive_hook));
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1)); // lets this example run for some time
|
||||
|
||||
cleanup(ctx, sess, receiver);
|
||||
}
|
||||
|
||||
TEST(RTPTests, rtp_poll)
|
||||
{
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
|
||||
EXPECT_NE(nullptr, sess);
|
||||
|
||||
int flags = RCE_NO_FLAGS;
|
||||
uvgrtp::media_stream* receiver = sess->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_H265, flags);
|
||||
EXPECT_NE(nullptr, receiver);
|
||||
|
||||
uvgrtp::frame::rtp_frame* frame = nullptr;
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rtp_errno = RTP_OK;
|
||||
|
||||
while (std::chrono::steady_clock::now() - start < std::chrono::seconds(1))
|
||||
{
|
||||
frame = receiver->pull_frame(3);
|
||||
|
||||
EXPECT_EQ(RTP_OK, rtp_errno);
|
||||
|
||||
if (frame)
|
||||
process_rtp_frame(frame);
|
||||
}
|
||||
|
||||
sess->destroy_stream(receiver);
|
||||
|
||||
|
||||
cleanup(ctx, sess, receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rtp_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame)
|
||||
{
|
||||
process_rtp_frame(frame);
|
||||
}
|
||||
|
||||
void cleanup(uvgrtp::context& ctx, uvgrtp::session* sess, uvgrtp::media_stream* ms)
|
||||
{
|
||||
if (ms)
|
||||
{
|
||||
sess->destroy_stream(ms);
|
||||
}
|
||||
|
||||
if (sess)
|
||||
{
|
||||
ctx.destroy_session(sess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_rtp_frame(uvgrtp::frame::rtp_frame* frame)
|
||||
{
|
||||
EXPECT_NE(0, frame->payload_len);
|
||||
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include "lib.hh"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(VersionTests, version) {
|
||||
EXPECT_STRNE("", uvgrtp::get_version().c_str());
|
||||
}
|
Loading…
Reference in New Issue