1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/buffered_socket_writer.h"
6
7#include <stdlib.h>
8
9#include "base/bind.h"
10#include "base/message_loop/message_loop.h"
11#include "base/run_loop.h"
12#include "net/base/io_buffer.h"
13#include "net/base/net_errors.h"
14#include "remoting/protocol/fake_session.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace remoting {
19namespace protocol {
20
21namespace {
22const int kTestBufferSize = 10 * 1024; // 10k;
23const size_t kWriteChunkSize = 1024U;
24}  // namespace
25
26class BufferedSocketWriterTest : public testing::Test {
27 public:
28  BufferedSocketWriterTest()
29      : write_error_(0) {
30  }
31
32  void OnDone() {
33    base::MessageLoop::current()->PostTask(FROM_HERE,
34                                           base::MessageLoop::QuitClosure());
35  }
36
37  void DestroyWriterAndQuit() {
38    written_data_ = socket_->written_data();
39    writer_.reset();
40    socket_.reset();
41    base::MessageLoop::current()->PostTask(FROM_HERE,
42                                           base::MessageLoop::QuitClosure());
43  }
44
45  void Unexpected() {
46    EXPECT_TRUE(false);
47  }
48
49 protected:
50  virtual void SetUp() OVERRIDE {
51    socket_.reset(new FakeStreamSocket());
52    writer_.reset(new BufferedSocketWriter());
53    writer_->Init(socket_.get(), base::Bind(
54        &BufferedSocketWriterTest::OnWriteFailed, base::Unretained(this)));
55    test_buffer_ = new net::IOBufferWithSize(kTestBufferSize);
56    test_buffer_2_ = new net::IOBufferWithSize(kTestBufferSize);
57    for (int i = 0; i< kTestBufferSize; ++i) {
58      test_buffer_->data()[i] = rand() % 256;
59      test_buffer_2_->data()[i] = rand() % 256;
60    }
61  }
62
63  void OnWriteFailed(int error) {
64    write_error_ = error;
65  }
66
67  void TestWrite() {
68    writer_->Write(test_buffer_, base::Bind(&BufferedSocketWriterTest::OnDone,
69                                            base::Unretained(this)));
70    writer_->Write(test_buffer_2_, base::Bind(&BufferedSocketWriterTest::OnDone,
71                                              base::Unretained(this)));
72    message_loop_.Run();
73    ASSERT_EQ(static_cast<size_t>(test_buffer_->size() +
74                                  test_buffer_2_->size()),
75              socket_->written_data().size());
76    EXPECT_EQ(0, memcmp(test_buffer_->data(), socket_->written_data().data(),
77                        test_buffer_->size()));
78    EXPECT_EQ(0, memcmp(test_buffer_2_->data(),
79                        socket_->written_data().data() + test_buffer_->size(),
80                        test_buffer_2_->size()));
81  }
82
83  void TestAppendInCallback() {
84    writer_->Write(test_buffer_, base::Bind(
85        base::IgnoreResult(&BufferedSocketWriterBase::Write),
86        base::Unretained(writer_.get()), test_buffer_2_,
87        base::Bind(&BufferedSocketWriterTest::OnDone,
88                  base::Unretained(this))));
89    message_loop_.Run();
90    ASSERT_EQ(static_cast<size_t>(test_buffer_->size() +
91                                  test_buffer_2_->size()),
92              socket_->written_data().size());
93    EXPECT_EQ(0, memcmp(test_buffer_->data(), socket_->written_data().data(),
94                        test_buffer_->size()));
95    EXPECT_EQ(0, memcmp(test_buffer_2_->data(),
96                        socket_->written_data().data() + test_buffer_->size(),
97                        test_buffer_2_->size()));
98  }
99
100  base::MessageLoop message_loop_;
101  scoped_ptr<FakeStreamSocket> socket_;
102  scoped_ptr<BufferedSocketWriter> writer_;
103  scoped_refptr<net::IOBufferWithSize> test_buffer_;
104  scoped_refptr<net::IOBufferWithSize> test_buffer_2_;
105  std::string written_data_;
106  int write_error_;
107};
108
109// Test synchronous write.
110TEST_F(BufferedSocketWriterTest, WriteFull) {
111  TestWrite();
112}
113
114// Test synchronous write in 1k chunks.
115TEST_F(BufferedSocketWriterTest, WriteChunks) {
116  socket_->set_write_limit(kWriteChunkSize);
117  TestWrite();
118}
119
120// Test asynchronous write.
121TEST_F(BufferedSocketWriterTest, WriteAsync) {
122  socket_->set_async_write(true);
123  socket_->set_write_limit(kWriteChunkSize);
124  TestWrite();
125}
126
127// Make sure we can call Write() from the done callback.
128TEST_F(BufferedSocketWriterTest, AppendInCallbackSync) {
129  TestAppendInCallback();
130}
131
132// Make sure we can call Write() from the done callback.
133TEST_F(BufferedSocketWriterTest, AppendInCallbackAsync) {
134  socket_->set_async_write(true);
135  socket_->set_write_limit(kWriteChunkSize);
136  TestAppendInCallback();
137}
138
139// Test that the writer can be destroyed from callback.
140TEST_F(BufferedSocketWriterTest, DestroyFromCallback) {
141  socket_->set_async_write(true);
142  writer_->Write(test_buffer_, base::Bind(
143      &BufferedSocketWriterTest::DestroyWriterAndQuit,
144      base::Unretained(this)));
145  writer_->Write(test_buffer_2_, base::Bind(
146      &BufferedSocketWriterTest::Unexpected,
147      base::Unretained(this)));
148  socket_->set_async_write(false);
149  message_loop_.Run();
150  ASSERT_GE(written_data_.size(),
151            static_cast<size_t>(test_buffer_->size()));
152  EXPECT_EQ(0, memcmp(test_buffer_->data(), written_data_.data(),
153                      test_buffer_->size()));
154}
155
156// Verify that it stops writing after the first error.
157TEST_F(BufferedSocketWriterTest, TestWriteErrorSync) {
158  socket_->set_write_limit(kWriteChunkSize);
159  writer_->Write(test_buffer_, base::Closure());
160  socket_->set_async_write(true);
161  writer_->Write(test_buffer_2_,
162                 base::Bind(&BufferedSocketWriterTest::Unexpected,
163                            base::Unretained(this)));
164  socket_->set_next_write_error(net::ERR_FAILED);
165  socket_->set_async_write(false);
166  base::RunLoop().RunUntilIdle();
167  EXPECT_EQ(net::ERR_FAILED, write_error_);
168  EXPECT_EQ(static_cast<size_t>(test_buffer_->size()),
169            socket_->written_data().size());
170}
171
172// Verify that it stops writing after the first error.
173TEST_F(BufferedSocketWriterTest, TestWriteErrorAsync) {
174  socket_->set_write_limit(kWriteChunkSize);
175  writer_->Write(test_buffer_, base::Closure());
176  socket_->set_async_write(true);
177  writer_->Write(test_buffer_2_,
178                 base::Bind(&BufferedSocketWriterTest::Unexpected,
179                            base::Unretained(this)));
180  socket_->set_next_write_error(net::ERR_FAILED);
181  base::RunLoop().RunUntilIdle();
182  EXPECT_EQ(net::ERR_FAILED, write_error_);
183  EXPECT_EQ(static_cast<size_t>(test_buffer_->size()),
184            socket_->written_data().size());
185}
186
187}  // namespace protocol
188}  // namespace remoting
189
190