diff options
Diffstat (limited to 'Plugins/jingle/libjingle/talk/base/virtualsocket_unittest.cc')
-rw-r--r-- | Plugins/jingle/libjingle/talk/base/virtualsocket_unittest.cc | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/Plugins/jingle/libjingle/talk/base/virtualsocket_unittest.cc b/Plugins/jingle/libjingle/talk/base/virtualsocket_unittest.cc new file mode 100644 index 0000000..16456a2 --- /dev/null +++ b/Plugins/jingle/libjingle/talk/base/virtualsocket_unittest.cc @@ -0,0 +1,239 @@ +// Copyright 2006, Google Inc. + +#include <complex> +#include <iostream> +#include <cassert> + +#include "talk/base/thread.h" +#include "talk/base/virtualsocketserver.h" +#include "talk/base/testclient.h" +#include "talk/base/time.h" + +#ifdef POSIX +extern "C" { +#include <errno.h> +} +#endif // POSIX + +using namespace talk_base; + +void test_basic(Thread* thread, VirtualSocketServer* ss) { + std::cout << "basic: "; + std::cout.flush(); + + SocketAddress addr1(ss->GetNextIP(), 5000); + AsyncUDPSocket* socket = CreateAsyncUDPSocket(ss); + socket->Bind(addr1); + + TestClient* client1 = new TestClient(socket); + TestClient* client2 = new TestClient(CreateAsyncUDPSocket(ss)); + + SocketAddress addr2; + client2->SendTo("foo", 3, addr1); + client1->CheckNextPacket("foo", 3, &addr2); + + SocketAddress addr3; + client1->SendTo("bizbaz", 6, addr2); + client2->CheckNextPacket("bizbaz", 6, &addr3); + assert(addr3 == addr1); + + for (int i = 0; i < 10; i++) { + client2 = new TestClient(CreateAsyncUDPSocket(ss)); + + SocketAddress addr4; + client2->SendTo("foo", 3, addr1); + client1->CheckNextPacket("foo", 3, &addr4); + assert((addr4.ip() == addr2.ip()) && (addr4.port() == addr2.port() + 1)); + + SocketAddress addr5; + client1->SendTo("bizbaz", 6, addr4); + client2->CheckNextPacket("bizbaz", 6, &addr5); + assert(addr5 == addr1); + + addr2 = addr4; + } + + std::cout << "PASS" << std::endl; +} + +// Sends at a constant rate but with random packet sizes. +struct Sender : public MessageHandler { + Sender(Thread* th, AsyncUDPSocket* s, uint32 rt) + : thread(th), socket(s), done(false), rate(rt), count(0) { + last_send = GetMillisecondCount(); + thread->PostDelayed(NextDelay(), this, 1); + } + + uint32 NextDelay() { + uint32 size = (rand() % 4096) + 1; + return 1000 * size / rate; + } + + void OnMessage(Message* pmsg) { + assert(pmsg->message_id == 1); + + if (done) + return; + + uint32 cur_time = GetMillisecondCount(); + uint32 delay = cur_time - last_send; + uint32 size = rate * delay / 1000; + size = std::min(size, uint32(4096)); + size = std::max(size, uint32(4)); + + count += size; + *reinterpret_cast<uint32*>(dummy) = cur_time; + socket->Send(dummy, size); + + last_send = cur_time; + thread->PostDelayed(NextDelay(), this, 1); + } + + Thread* thread; + AsyncUDPSocket* socket; + bool done; + uint32 rate; // bytes per second + uint32 count; + uint32 last_send; + char dummy[4096]; +}; + +struct Receiver : public MessageHandler, public sigslot::has_slots<> { + Receiver(Thread* th, AsyncUDPSocket* s, uint32 bw) + : thread(th), socket(s), bandwidth(bw), done(false), count(0), + sec_count(0), sum(0), sum_sq(0), samples(0) { + socket->SignalReadPacket.connect(this, &Receiver::OnReadPacket); + thread->PostDelayed(1000, this, 1); + } + + ~Receiver() { + thread->Clear(this); + } + + void OnReadPacket( + const char* data, size_t size, const SocketAddress& remote_addr, + AsyncPacketSocket* s) { + assert(s == socket); + assert(size >= 4); + + count += size; + sec_count += size; + + uint32 send_time = *reinterpret_cast<const uint32*>(data); + uint32 recv_time = GetMillisecondCount(); + uint32 delay = recv_time - send_time; + sum += delay; + sum_sq += delay * delay; + samples += 1; + } + + void OnMessage(Message* pmsg) { + assert(pmsg->message_id == 1); + // It is always possible for us to receive more than expected because + // packets can be further delayed in delivery. + if (bandwidth > 0) + assert(sec_count <= 5 * bandwidth / 4); + sec_count = 0; + thread->PostDelayed(1000, this, 1); + } + + Thread* thread; + AsyncUDPSocket* socket; + uint32 bandwidth; + bool done; + uint32 count; + uint32 sec_count; + double sum; + double sum_sq; + uint32 samples; +}; + +void test_bandwidth(Thread* thread, VirtualSocketServer* ss) { + std::cout << "bandwidth: "; + std::cout.flush(); + + AsyncUDPSocket* send_socket = CreateAsyncUDPSocket(ss); + AsyncUDPSocket* recv_socket = CreateAsyncUDPSocket(ss); + assert(send_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0); + assert(recv_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0); + assert(send_socket->Connect(recv_socket->GetLocalAddress()) >= 0); + + uint32 bandwidth = 64 * 1024; + ss->set_bandwidth(bandwidth); + + Sender sender(thread, send_socket, 80 * 1024); + Receiver receiver(thread, recv_socket, bandwidth); + + Thread* pthMain = Thread::Current(); + pthMain->ProcessMessages(5000); + sender.done = true; + pthMain->ProcessMessages(5000); + + assert(receiver.count >= 5 * 3 * bandwidth / 4); + assert(receiver.count <= 6 * bandwidth); // queue could drain for 1 sec + + delete send_socket; + delete recv_socket; + + ss->set_bandwidth(0); + + std::cout << "PASS" << std::endl; +} + +void test_delay(Thread* thread, VirtualSocketServer* ss) { + std::cout << "delay: "; + std::cout.flush(); + + uint32 mean = 2000; + uint32 stddev = 500; + + ss->set_delay_mean(mean); + ss->set_delay_stddev(stddev); + ss->UpdateDelayDistribution(); + + AsyncUDPSocket* send_socket = CreateAsyncUDPSocket(ss); + AsyncUDPSocket* recv_socket = CreateAsyncUDPSocket(ss); + assert(send_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0); + assert(recv_socket->Bind(SocketAddress(ss->GetNextIP(), 1000)) >= 0); + assert(send_socket->Connect(recv_socket->GetLocalAddress()) >= 0); + + Sender sender(thread, send_socket, 64 * 1024); + Receiver receiver(thread, recv_socket, 0); + + Thread* pthMain = Thread::Current(); + pthMain->ProcessMessages(5000); + sender.done = true; + pthMain->ProcessMessages(5000); + + double sample_mean = receiver.sum / receiver.samples; + double num = receiver.sum_sq - 2 * sample_mean * receiver.sum + + receiver.samples * sample_mean * sample_mean; + double sample_stddev = std::sqrt(num / (receiver.samples - 1)); +std::cout << "mean=" << sample_mean << " dev=" << sample_stddev << std::endl; + + assert(0.9 * mean <= sample_mean); + assert(sample_mean <= 1.1 * mean); + assert(0.9 * stddev <= sample_stddev); + assert(sample_stddev <= 1.1 * stddev); + + delete send_socket; + delete recv_socket; + + ss->set_delay_mean(0); + ss->set_delay_stddev(0); + ss->UpdateDelayDistribution(); + + std::cout << "PASS" << std::endl; +} + +int main(int argc, char* argv) { + Thread *pthMain = Thread::Current(); + VirtualSocketServer* ss = new VirtualSocketServer(); + pthMain->set_socketserver(ss); + + test_basic(pthMain, ss); + test_bandwidth(pthMain, ss); + test_delay(pthMain, ss); + + return 0; +} |