普通文本  |  190行  |  6.39 KB

// 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 "remoting/protocol/buffered_socket_writer.h"

#include <stdlib.h>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "remoting/protocol/fake_session.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace remoting {
namespace protocol {

namespace {
const int kTestBufferSize = 10 * 1024; // 10k;
const size_t kWriteChunkSize = 1024U;
}  // namespace

class BufferedSocketWriterTest : public testing::Test {
 public:
  BufferedSocketWriterTest()
      : write_error_(0) {
  }

  void OnDone() {
    base::MessageLoop::current()->PostTask(FROM_HERE,
                                           base::MessageLoop::QuitClosure());
  }

  void DestroyWriterAndQuit() {
    written_data_ = socket_->written_data();
    writer_.reset();
    socket_.reset();
    base::MessageLoop::current()->PostTask(FROM_HERE,
                                           base::MessageLoop::QuitClosure());
  }

  void Unexpected() {
    EXPECT_TRUE(false);
  }

 protected:
  virtual void SetUp() OVERRIDE {
    socket_.reset(new FakeSocket());
    writer_.reset(new BufferedSocketWriter());
    writer_->Init(socket_.get(), base::Bind(
        &BufferedSocketWriterTest::OnWriteFailed, base::Unretained(this)));
    test_buffer_ = new net::IOBufferWithSize(kTestBufferSize);
    test_buffer_2_ = new net::IOBufferWithSize(kTestBufferSize);
    for (int i = 0; i< kTestBufferSize; ++i) {
      test_buffer_->data()[i] = rand() % 256;
      test_buffer_2_->data()[i] = rand() % 256;
    }
  }

  void OnWriteFailed(int error) {
    write_error_ = error;
  }

  void TestWrite() {
    writer_->Write(test_buffer_, base::Bind(&BufferedSocketWriterTest::OnDone,
                                            base::Unretained(this)));
    writer_->Write(test_buffer_2_, base::Bind(&BufferedSocketWriterTest::OnDone,
                                              base::Unretained(this)));
    message_loop_.Run();
    ASSERT_EQ(static_cast<size_t>(test_buffer_->size() +
                                  test_buffer_2_->size()),
              socket_->written_data().size());
    EXPECT_EQ(0, memcmp(test_buffer_->data(), socket_->written_data().data(),
                        test_buffer_->size()));
    EXPECT_EQ(0, memcmp(test_buffer_2_->data(),
                        socket_->written_data().data() + test_buffer_->size(),
                        test_buffer_2_->size()));
  }

  void TestAppendInCallback() {
    writer_->Write(test_buffer_, base::Bind(
        base::IgnoreResult(&BufferedSocketWriterBase::Write),
        base::Unretained(writer_.get()), test_buffer_2_,
        base::Bind(&BufferedSocketWriterTest::OnDone,
                  base::Unretained(this))));
    message_loop_.Run();
    ASSERT_EQ(static_cast<size_t>(test_buffer_->size() +
                                  test_buffer_2_->size()),
              socket_->written_data().size());
    EXPECT_EQ(0, memcmp(test_buffer_->data(), socket_->written_data().data(),
                        test_buffer_->size()));
    EXPECT_EQ(0, memcmp(test_buffer_2_->data(),
                        socket_->written_data().data() + test_buffer_->size(),
                        test_buffer_2_->size()));
  }

  base::MessageLoop message_loop_;
  scoped_ptr<FakeSocket> socket_;
  scoped_ptr<BufferedSocketWriter> writer_;
  scoped_refptr<net::IOBufferWithSize> test_buffer_;
  scoped_refptr<net::IOBufferWithSize> test_buffer_2_;
  std::string written_data_;
  int write_error_;
};

// Test synchronous write.
TEST_F(BufferedSocketWriterTest, WriteFull) {
  TestWrite();
}

// Test synchronous write in 1k chunks.
TEST_F(BufferedSocketWriterTest, WriteChunks) {
  socket_->set_write_limit(kWriteChunkSize);
  TestWrite();
}

// Test asynchronous write.
TEST_F(BufferedSocketWriterTest, WriteAsync) {
  socket_->set_async_write(true);
  socket_->set_write_limit(kWriteChunkSize);
  TestWrite();
}

// Make sure we can call Write() from the done callback.
TEST_F(BufferedSocketWriterTest, AppendInCallbackSync) {
  TestAppendInCallback();
}

// Make sure we can call Write() from the done callback.
TEST_F(BufferedSocketWriterTest, AppendInCallbackAsync) {
  socket_->set_async_write(true);
  socket_->set_write_limit(kWriteChunkSize);
  TestAppendInCallback();
}

// Test that the writer can be destroyed from callback.
TEST_F(BufferedSocketWriterTest, DestroyFromCallback) {
  socket_->set_async_write(true);
  writer_->Write(test_buffer_, base::Bind(
      &BufferedSocketWriterTest::DestroyWriterAndQuit,
      base::Unretained(this)));
  writer_->Write(test_buffer_2_, base::Bind(
      &BufferedSocketWriterTest::Unexpected,
      base::Unretained(this)));
  socket_->set_async_write(false);
  message_loop_.Run();
  ASSERT_GE(written_data_.size(),
            static_cast<size_t>(test_buffer_->size()));
  EXPECT_EQ(0, memcmp(test_buffer_->data(), written_data_.data(),
                      test_buffer_->size()));
}

// Verify that it stops writing after the first error.
TEST_F(BufferedSocketWriterTest, TestWriteErrorSync) {
  socket_->set_write_limit(kWriteChunkSize);
  writer_->Write(test_buffer_, base::Closure());
  socket_->set_async_write(true);
  writer_->Write(test_buffer_2_,
                 base::Bind(&BufferedSocketWriterTest::Unexpected,
                            base::Unretained(this)));
  socket_->set_next_write_error(net::ERR_FAILED);
  socket_->set_async_write(false);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::ERR_FAILED, write_error_);
  EXPECT_EQ(static_cast<size_t>(test_buffer_->size()),
            socket_->written_data().size());
}

// Verify that it stops writing after the first error.
TEST_F(BufferedSocketWriterTest, TestWriteErrorAsync) {
  socket_->set_write_limit(kWriteChunkSize);
  writer_->Write(test_buffer_, base::Closure());
  socket_->set_async_write(true);
  writer_->Write(test_buffer_2_,
                 base::Bind(&BufferedSocketWriterTest::Unexpected,
                            base::Unretained(this)));
  socket_->set_next_write_error(net::ERR_FAILED);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(net::ERR_FAILED, write_error_);
  EXPECT_EQ(static_cast<size_t>(test_buffer_->size()),
            socket_->written_data().size());
}

}  // namespace protocol
}  // namespace remoting