| Index: jingle/glue/pseudotcp_adapter_unittest.cc
|
| diff --git a/jingle/glue/pseudotcp_adapter_unittest.cc b/jingle/glue/pseudotcp_adapter_unittest.cc
|
| deleted file mode 100644
|
| index 212a2d06dd32b76e4f40e9fd86436d5c4a9ef8c9..0000000000000000000000000000000000000000
|
| --- a/jingle/glue/pseudotcp_adapter_unittest.cc
|
| +++ /dev/null
|
| @@ -1,444 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "jingle/glue/pseudotcp_adapter.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/compiler_specific.h"
|
| -#include "jingle/glue/thread_wrapper.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/test_completion_callback.h"
|
| -#include "net/udp/udp_socket.h"
|
| -#include "testing/gmock/include/gmock/gmock.h"
|
| -#include "testing/gtest/include/gtest/gtest.h"
|
| -
|
| -
|
| -namespace jingle_glue {
|
| -namespace {
|
| -class FakeSocket;
|
| -} // namespace
|
| -} // namespace jingle_glue
|
| -
|
| -namespace jingle_glue {
|
| -
|
| -namespace {
|
| -
|
| -const int kMessageSize = 1024;
|
| -const int kMessages = 100;
|
| -const int kTestDataSize = kMessages * kMessageSize;
|
| -
|
| -class RateLimiter {
|
| - public:
|
| - virtual ~RateLimiter() { };
|
| - // Returns true if the new packet needs to be dropped, false otherwise.
|
| - virtual bool DropNextPacket() = 0;
|
| -};
|
| -
|
| -class LeakyBucket : public RateLimiter {
|
| - public:
|
| - // |rate| is in drops per second.
|
| - LeakyBucket(double volume, double rate)
|
| - : volume_(volume),
|
| - rate_(rate),
|
| - level_(0.0),
|
| - last_update_(base::TimeTicks::Now()) {
|
| - }
|
| -
|
| - ~LeakyBucket() override {}
|
| -
|
| - bool DropNextPacket() override {
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| - double interval = (now - last_update_).InSecondsF();
|
| - last_update_ = now;
|
| - level_ = level_ + 1.0 - interval * rate_;
|
| - if (level_ > volume_) {
|
| - level_ = volume_;
|
| - return true;
|
| - } else if (level_ < 0.0) {
|
| - level_ = 0.0;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private:
|
| - double volume_;
|
| - double rate_;
|
| - double level_;
|
| - base::TimeTicks last_update_;
|
| -};
|
| -
|
| -class FakeSocket : public net::Socket {
|
| - public:
|
| - FakeSocket()
|
| - : rate_limiter_(NULL),
|
| - latency_ms_(0) {
|
| - }
|
| - ~FakeSocket() override {}
|
| -
|
| - void AppendInputPacket(const std::vector<char>& data) {
|
| - if (rate_limiter_ && rate_limiter_->DropNextPacket())
|
| - return; // Lose the packet.
|
| -
|
| - if (!read_callback_.is_null()) {
|
| - int size = std::min(read_buffer_size_, static_cast<int>(data.size()));
|
| - memcpy(read_buffer_->data(), &data[0], data.size());
|
| - net::CompletionCallback cb = read_callback_;
|
| - read_callback_.Reset();
|
| - read_buffer_ = NULL;
|
| - cb.Run(size);
|
| - } else {
|
| - incoming_packets_.push_back(data);
|
| - }
|
| - }
|
| -
|
| - void Connect(FakeSocket* peer_socket) {
|
| - peer_socket_ = peer_socket;
|
| - }
|
| -
|
| - void set_rate_limiter(RateLimiter* rate_limiter) {
|
| - rate_limiter_ = rate_limiter;
|
| - };
|
| -
|
| - void set_latency(int latency_ms) { latency_ms_ = latency_ms; };
|
| -
|
| - // net::Socket interface.
|
| - int Read(net::IOBuffer* buf,
|
| - int buf_len,
|
| - const net::CompletionCallback& callback) override {
|
| - CHECK(read_callback_.is_null());
|
| - CHECK(buf);
|
| -
|
| - if (incoming_packets_.size() > 0) {
|
| - scoped_refptr<net::IOBuffer> buffer(buf);
|
| - int size = std::min(
|
| - static_cast<int>(incoming_packets_.front().size()), buf_len);
|
| - memcpy(buffer->data(), &*incoming_packets_.front().begin(), size);
|
| - incoming_packets_.pop_front();
|
| - return size;
|
| - } else {
|
| - read_callback_ = callback;
|
| - read_buffer_ = buf;
|
| - read_buffer_size_ = buf_len;
|
| - return net::ERR_IO_PENDING;
|
| - }
|
| - }
|
| -
|
| - int Write(net::IOBuffer* buf,
|
| - int buf_len,
|
| - const net::CompletionCallback& callback) override {
|
| - DCHECK(buf);
|
| - if (peer_socket_) {
|
| - base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&FakeSocket::AppendInputPacket,
|
| - base::Unretained(peer_socket_),
|
| - std::vector<char>(buf->data(), buf->data() + buf_len)),
|
| - base::TimeDelta::FromMilliseconds(latency_ms_));
|
| - }
|
| -
|
| - return buf_len;
|
| - }
|
| -
|
| - int SetReceiveBufferSize(int32 size) override {
|
| - NOTIMPLEMENTED();
|
| - return net::ERR_NOT_IMPLEMENTED;
|
| - }
|
| - int SetSendBufferSize(int32 size) override {
|
| - NOTIMPLEMENTED();
|
| - return net::ERR_NOT_IMPLEMENTED;
|
| - }
|
| -
|
| - private:
|
| - scoped_refptr<net::IOBuffer> read_buffer_;
|
| - int read_buffer_size_;
|
| - net::CompletionCallback read_callback_;
|
| -
|
| - std::deque<std::vector<char> > incoming_packets_;
|
| -
|
| - FakeSocket* peer_socket_;
|
| - RateLimiter* rate_limiter_;
|
| - int latency_ms_;
|
| -};
|
| -
|
| -class TCPChannelTester : public base::RefCountedThreadSafe<TCPChannelTester> {
|
| - public:
|
| - TCPChannelTester(base::MessageLoop* message_loop,
|
| - net::Socket* client_socket,
|
| - net::Socket* host_socket)
|
| - : message_loop_(message_loop),
|
| - host_socket_(host_socket),
|
| - client_socket_(client_socket),
|
| - done_(false),
|
| - write_errors_(0),
|
| - read_errors_(0) {}
|
| -
|
| - void Start() {
|
| - message_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&TCPChannelTester::DoStart, this));
|
| - }
|
| -
|
| - void CheckResults() {
|
| - EXPECT_EQ(0, write_errors_);
|
| - EXPECT_EQ(0, read_errors_);
|
| -
|
| - ASSERT_EQ(kTestDataSize + kMessageSize, input_buffer_->capacity());
|
| -
|
| - output_buffer_->SetOffset(0);
|
| - ASSERT_EQ(kTestDataSize, output_buffer_->size());
|
| -
|
| - EXPECT_EQ(0, memcmp(output_buffer_->data(),
|
| - input_buffer_->StartOfBuffer(), kTestDataSize));
|
| - }
|
| -
|
| - protected:
|
| - virtual ~TCPChannelTester() {}
|
| -
|
| - void Done() {
|
| - done_ = true;
|
| - message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
|
| - }
|
| -
|
| - void DoStart() {
|
| - InitBuffers();
|
| - DoRead();
|
| - DoWrite();
|
| - }
|
| -
|
| - void InitBuffers() {
|
| - output_buffer_ = new net::DrainableIOBuffer(
|
| - new net::IOBuffer(kTestDataSize), kTestDataSize);
|
| - memset(output_buffer_->data(), 123, kTestDataSize);
|
| -
|
| - input_buffer_ = new net::GrowableIOBuffer();
|
| - // Always keep kMessageSize bytes available at the end of the input buffer.
|
| - input_buffer_->SetCapacity(kMessageSize);
|
| - }
|
| -
|
| - void DoWrite() {
|
| - int result = 1;
|
| - while (result > 0) {
|
| - if (output_buffer_->BytesRemaining() == 0)
|
| - break;
|
| -
|
| - int bytes_to_write = std::min(output_buffer_->BytesRemaining(),
|
| - kMessageSize);
|
| - result = client_socket_->Write(
|
| - output_buffer_.get(),
|
| - bytes_to_write,
|
| - base::Bind(&TCPChannelTester::OnWritten, base::Unretained(this)));
|
| - HandleWriteResult(result);
|
| - }
|
| - }
|
| -
|
| - void OnWritten(int result) {
|
| - HandleWriteResult(result);
|
| - DoWrite();
|
| - }
|
| -
|
| - void HandleWriteResult(int result) {
|
| - if (result <= 0 && result != net::ERR_IO_PENDING) {
|
| - LOG(ERROR) << "Received error " << result << " when trying to write";
|
| - write_errors_++;
|
| - Done();
|
| - } else if (result > 0) {
|
| - output_buffer_->DidConsume(result);
|
| - }
|
| - }
|
| -
|
| - void DoRead() {
|
| - int result = 1;
|
| - while (result > 0) {
|
| - input_buffer_->set_offset(input_buffer_->capacity() - kMessageSize);
|
| -
|
| - result = host_socket_->Read(
|
| - input_buffer_.get(),
|
| - kMessageSize,
|
| - base::Bind(&TCPChannelTester::OnRead, base::Unretained(this)));
|
| - HandleReadResult(result);
|
| - };
|
| - }
|
| -
|
| - void OnRead(int result) {
|
| - HandleReadResult(result);
|
| - DoRead();
|
| - }
|
| -
|
| - void HandleReadResult(int result) {
|
| - if (result <= 0 && result != net::ERR_IO_PENDING) {
|
| - if (!done_) {
|
| - LOG(ERROR) << "Received error " << result << " when trying to read";
|
| - read_errors_++;
|
| - Done();
|
| - }
|
| - } else if (result > 0) {
|
| - // Allocate memory for the next read.
|
| - input_buffer_->SetCapacity(input_buffer_->capacity() + result);
|
| - if (input_buffer_->capacity() == kTestDataSize + kMessageSize)
|
| - Done();
|
| - }
|
| - }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<TCPChannelTester>;
|
| -
|
| - base::MessageLoop* message_loop_;
|
| - net::Socket* host_socket_;
|
| - net::Socket* client_socket_;
|
| - bool done_;
|
| -
|
| - scoped_refptr<net::DrainableIOBuffer> output_buffer_;
|
| - scoped_refptr<net::GrowableIOBuffer> input_buffer_;
|
| -
|
| - int write_errors_;
|
| - int read_errors_;
|
| -};
|
| -
|
| -class PseudoTcpAdapterTest : public testing::Test {
|
| - protected:
|
| - void SetUp() override {
|
| - JingleThreadWrapper::EnsureForCurrentMessageLoop();
|
| -
|
| - host_socket_ = new FakeSocket();
|
| - client_socket_ = new FakeSocket();
|
| -
|
| - host_socket_->Connect(client_socket_);
|
| - client_socket_->Connect(host_socket_);
|
| -
|
| - host_pseudotcp_.reset(new PseudoTcpAdapter(host_socket_));
|
| - client_pseudotcp_.reset(new PseudoTcpAdapter(client_socket_));
|
| - }
|
| -
|
| - FakeSocket* host_socket_;
|
| - FakeSocket* client_socket_;
|
| -
|
| - scoped_ptr<PseudoTcpAdapter> host_pseudotcp_;
|
| - scoped_ptr<PseudoTcpAdapter> client_pseudotcp_;
|
| - base::MessageLoop message_loop_;
|
| -};
|
| -
|
| -TEST_F(PseudoTcpAdapterTest, DataTransfer) {
|
| - net::TestCompletionCallback host_connect_cb;
|
| - net::TestCompletionCallback client_connect_cb;
|
| -
|
| - int rv1 = host_pseudotcp_->Connect(host_connect_cb.callback());
|
| - int rv2 = client_pseudotcp_->Connect(client_connect_cb.callback());
|
| -
|
| - if (rv1 == net::ERR_IO_PENDING)
|
| - rv1 = host_connect_cb.WaitForResult();
|
| - if (rv2 == net::ERR_IO_PENDING)
|
| - rv2 = client_connect_cb.WaitForResult();
|
| - ASSERT_EQ(net::OK, rv1);
|
| - ASSERT_EQ(net::OK, rv2);
|
| -
|
| - scoped_refptr<TCPChannelTester> tester =
|
| - new TCPChannelTester(&message_loop_, host_pseudotcp_.get(),
|
| - client_pseudotcp_.get());
|
| -
|
| - tester->Start();
|
| - message_loop_.Run();
|
| - tester->CheckResults();
|
| -}
|
| -
|
| -TEST_F(PseudoTcpAdapterTest, LimitedChannel) {
|
| - const int kLatencyMs = 20;
|
| - const int kPacketsPerSecond = 400;
|
| - const int kBurstPackets = 10;
|
| -
|
| - LeakyBucket host_limiter(kBurstPackets, kPacketsPerSecond);
|
| - host_socket_->set_latency(kLatencyMs);
|
| - host_socket_->set_rate_limiter(&host_limiter);
|
| -
|
| - LeakyBucket client_limiter(kBurstPackets, kPacketsPerSecond);
|
| - host_socket_->set_latency(kLatencyMs);
|
| - client_socket_->set_rate_limiter(&client_limiter);
|
| -
|
| - net::TestCompletionCallback host_connect_cb;
|
| - net::TestCompletionCallback client_connect_cb;
|
| -
|
| - int rv1 = host_pseudotcp_->Connect(host_connect_cb.callback());
|
| - int rv2 = client_pseudotcp_->Connect(client_connect_cb.callback());
|
| -
|
| - if (rv1 == net::ERR_IO_PENDING)
|
| - rv1 = host_connect_cb.WaitForResult();
|
| - if (rv2 == net::ERR_IO_PENDING)
|
| - rv2 = client_connect_cb.WaitForResult();
|
| - ASSERT_EQ(net::OK, rv1);
|
| - ASSERT_EQ(net::OK, rv2);
|
| -
|
| - scoped_refptr<TCPChannelTester> tester =
|
| - new TCPChannelTester(&message_loop_, host_pseudotcp_.get(),
|
| - client_pseudotcp_.get());
|
| -
|
| - tester->Start();
|
| - message_loop_.Run();
|
| - tester->CheckResults();
|
| -}
|
| -
|
| -class DeleteOnConnected {
|
| - public:
|
| - DeleteOnConnected(base::MessageLoop* message_loop,
|
| - scoped_ptr<PseudoTcpAdapter>* adapter)
|
| - : message_loop_(message_loop), adapter_(adapter) {}
|
| - void OnConnected(int error) {
|
| - adapter_->reset();
|
| - message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
|
| - }
|
| - base::MessageLoop* message_loop_;
|
| - scoped_ptr<PseudoTcpAdapter>* adapter_;
|
| -};
|
| -
|
| -TEST_F(PseudoTcpAdapterTest, DeleteOnConnected) {
|
| - // This test verifies that deleting the adapter mid-callback doesn't lead
|
| - // to deleted structures being touched as the stack unrolls, so the failure
|
| - // mode is a crash rather than a normal test failure.
|
| - net::TestCompletionCallback client_connect_cb;
|
| - DeleteOnConnected host_delete(&message_loop_, &host_pseudotcp_);
|
| -
|
| - host_pseudotcp_->Connect(base::Bind(&DeleteOnConnected::OnConnected,
|
| - base::Unretained(&host_delete)));
|
| - client_pseudotcp_->Connect(client_connect_cb.callback());
|
| - message_loop_.Run();
|
| -
|
| - ASSERT_EQ(NULL, host_pseudotcp_.get());
|
| -}
|
| -
|
| -// Verify that we can send/receive data with the write-waits-for-send
|
| -// flag set.
|
| -TEST_F(PseudoTcpAdapterTest, WriteWaitsForSendLetsDataThrough) {
|
| - net::TestCompletionCallback host_connect_cb;
|
| - net::TestCompletionCallback client_connect_cb;
|
| -
|
| - host_pseudotcp_->SetWriteWaitsForSend(true);
|
| - client_pseudotcp_->SetWriteWaitsForSend(true);
|
| -
|
| - // Disable Nagle's algorithm because the test is slow when it is
|
| - // enabled.
|
| - host_pseudotcp_->SetNoDelay(true);
|
| -
|
| - int rv1 = host_pseudotcp_->Connect(host_connect_cb.callback());
|
| - int rv2 = client_pseudotcp_->Connect(client_connect_cb.callback());
|
| -
|
| - if (rv1 == net::ERR_IO_PENDING)
|
| - rv1 = host_connect_cb.WaitForResult();
|
| - if (rv2 == net::ERR_IO_PENDING)
|
| - rv2 = client_connect_cb.WaitForResult();
|
| - ASSERT_EQ(net::OK, rv1);
|
| - ASSERT_EQ(net::OK, rv2);
|
| -
|
| - scoped_refptr<TCPChannelTester> tester =
|
| - new TCPChannelTester(&message_loop_, host_pseudotcp_.get(),
|
| - client_pseudotcp_.get());
|
| -
|
| - tester->Start();
|
| - message_loop_.Run();
|
| - tester->CheckResults();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -} // namespace jingle_glue
|
|
|