summaryrefslogtreecommitdiffstats
path: root/base/async_socket_io_handler_unittest.cc
blob: 2b0e3c25c30af9d09949c3bda4248846a61caf4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright 2013 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 "base/async_socket_io_handler.h"

#include "base/bind.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {
const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
const size_t kAsyncSocketIoTestStringLength =
    arraysize(kAsyncSocketIoTestString);

class TestSocketReader {
 public:
  // Set |number_of_reads_before_quit| to >0 when you expect a specific number
  // of Read operations to complete.  Once that number is reached, the current
  // message loop will be Quit().  Set |number_of_reads_before_quit| to -1 if
  // callbacks should not be counted.
  TestSocketReader(base::CancelableSyncSocket* socket,
                   int number_of_reads_before_quit,
                   bool issue_reads_from_callback,
                   bool expect_eof)
      : socket_(socket), buffer_(),
        number_of_reads_before_quit_(number_of_reads_before_quit),
        callbacks_received_(0),
        issue_reads_from_callback_(issue_reads_from_callback),
        expect_eof_(expect_eof) {
    io_handler.Initialize(socket_->handle(),
                          base::Bind(&TestSocketReader::OnRead,
                                     base::Unretained(this)));
  }
  ~TestSocketReader() {}

  bool IssueRead() {
    return io_handler.Read(&buffer_[0], sizeof(buffer_));
  }

  const char* buffer() const { return &buffer_[0]; }

  int callbacks_received() const { return callbacks_received_; }

 private:
  void OnRead(int bytes_read) {
    if (!expect_eof_) {
      EXPECT_GT(bytes_read, 0);
    } else {
      EXPECT_GE(bytes_read, 0);
    }
    ++callbacks_received_;
    if (number_of_reads_before_quit_ == callbacks_received_) {
      base::MessageLoop::current()->Quit();
    } else if (issue_reads_from_callback_) {
      IssueRead();
    }
  }

  base::AsyncSocketIoHandler io_handler;
  base::CancelableSyncSocket* socket_;  // Ownership lies outside the class.
  char buffer_[kAsyncSocketIoTestStringLength];
  int number_of_reads_before_quit_;
  int callbacks_received_;
  bool issue_reads_from_callback_;
  bool expect_eof_;
};

// Workaround to be able to use a base::Closure for sending data.
// Send() returns int but a closure must return void.
void SendData(base::CancelableSyncSocket* socket,
              const void* buffer,
              size_t length) {
  socket->Send(buffer, length);
}

}  // end namespace.

// Tests doing a pending read from a socket and use an IO handler to get
// notified of data.
TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
  base::MessageLoopForIO loop;

  base::CancelableSyncSocket pair[2];
  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));

  TestSocketReader reader(&pair[0], 1, false, false);
  EXPECT_TRUE(reader.IssueRead());

  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
  base::MessageLoop::current()->Run();
  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
  EXPECT_EQ(1, reader.callbacks_received());
}

// Tests doing a read from a socket when we know that there is data in the
// socket.  Here we want to make sure that any async 'can read' notifications
// won't trip us off and that the synchronous case works as well.
TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
  base::MessageLoopForIO loop;

  base::CancelableSyncSocket pair[2];
  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));

  TestSocketReader reader(&pair[0], -1, false, false);

  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
      base::MessageLoop::QuitClosure(),
      base::TimeDelta::FromMilliseconds(100));
  base::MessageLoop::current()->Run();

  EXPECT_TRUE(reader.IssueRead());
  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
  // We've now verified that the read happened synchronously, but it's not
  // guaranteed that the callback has been issued since the callback will be
  // called asynchronously even though the read may have been done.
  // So we call RunUntilIdle() to allow any event notifications or APC's on
  // Windows, to execute before checking the count of how many callbacks we've
  // received.
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(1, reader.callbacks_received());
}

// Calls Read() from within a callback to test that simple read "loops" work.
TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
  base::MessageLoopForIO loop;

  base::CancelableSyncSocket pair[2];
  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));

  const int kReadOperationCount = 10;
  TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
  EXPECT_TRUE(reader.IssueRead());

  // Issue sends on an interval to satisfy the Read() requirements.
  int64 milliseconds = 0;
  for (int i = 0; i < kReadOperationCount; ++i) {
    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
        base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
            kAsyncSocketIoTestStringLength),
        base::TimeDelta::FromMilliseconds(milliseconds));
    milliseconds += 10;
  }

  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
      base::MessageLoop::QuitClosure(),
      base::TimeDelta::FromMilliseconds(100 + milliseconds));

  base::MessageLoop::current()->Run();
  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
}

// Calls Read() then close other end, check that a correct callback is received.
TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
  base::MessageLoopForIO loop;

  base::CancelableSyncSocket pair[2];
  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));

  const int kReadOperationCount = 1;
  TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
  EXPECT_TRUE(reader.IssueRead());

  pair[1].Close();

  base::MessageLoop::current()->Run();
  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
}