blob: ba056995a5503f72a06f45384979ba202e9427f4 [file] [log] [blame]
Paul Stewartf65320c2011-10-13 14:34:52 -07001// Copyright (c) 2011 The Chromium OS 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 "shill/async_connection.h"
6
7#include <netinet/in.h>
8
9#include <vector>
10
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/bind.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070012#include <gtest/gtest.h>
13
14#include "shill/ip_address.h"
15#include "shill/mock_event_dispatcher.h"
16#include "shill/mock_sockets.h"
17
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018using base::Bind;
19using base::Callback;
20using base::Unretained;
Paul Stewartf65320c2011-10-13 14:34:52 -070021using std::string;
22using ::testing::_;
23using ::testing::Return;
24using ::testing::ReturnNew;
25using ::testing::StrEq;
26using ::testing::StrictMock;
27using ::testing::Test;
28
29namespace shill {
30
31namespace {
32const char kInterfaceName[] = "int0";
33const char kConnectAddress[] = "10.11.12.13";
34const int kConnectPort = 10203;
35const int kErrorNumber = 30405;
36const int kSocketFD = 60708;
37} // namespace {}
38
39class AsyncConnectionTest : public Test {
40 public:
41 AsyncConnectionTest()
Paul Stewart8585b202012-09-21 14:03:01 -070042 : async_connection_(
43 new AsyncConnection(kInterfaceName, &dispatcher_, &sockets_,
44 callback_target_.callback())),
Paul Stewartf65320c2011-10-13 14:34:52 -070045 address_(IPAddress::kFamilyIPv4) { }
46
47 virtual void SetUp() {
48 EXPECT_TRUE(address_.SetAddressFromString(kConnectAddress));
49 }
50 virtual void TearDown() {
Paul Stewart8585b202012-09-21 14:03:01 -070051 if (async_connection_.get() && async_connection_->fd_ >= 0) {
Paul Stewartf65320c2011-10-13 14:34:52 -070052 EXPECT_CALL(sockets(), Close(kSocketFD))
53 .WillOnce(Return(0));
54 }
55 }
Paul Stewart8585b202012-09-21 14:03:01 -070056 void InvokeFreeConnection(bool /*success*/, int /*fd*/) {
57 async_connection_.reset();
58 }
Paul Stewartf65320c2011-10-13 14:34:52 -070059
60 protected:
61 class ConnectCallbackTarget {
62 public:
63 ConnectCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -050064 : callback_(Bind(&ConnectCallbackTarget::CallTarget,
65 Unretained(this))) {}
Paul Stewartf65320c2011-10-13 14:34:52 -070066
67 MOCK_METHOD2(CallTarget, void(bool success, int fd));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050068 const Callback<void(bool, int)> &callback() { return callback_; }
Paul Stewartf65320c2011-10-13 14:34:52 -070069
70 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -050071 Callback<void(bool, int)> callback_;
Paul Stewartf65320c2011-10-13 14:34:52 -070072 };
73
74 void ExpectReset() {
Paul Stewart8585b202012-09-21 14:03:01 -070075 EXPECT_STREQ(kInterfaceName, async_connection_->interface_name_.c_str());
76 EXPECT_EQ(&dispatcher_, async_connection_->dispatcher_);
77 EXPECT_EQ(&sockets_, async_connection_->sockets_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050078 EXPECT_TRUE(callback_target_.callback().
Paul Stewart8585b202012-09-21 14:03:01 -070079 Equals(async_connection_->callback_));
80 EXPECT_EQ(-1, async_connection_->fd_);
81 EXPECT_FALSE(async_connection_->connect_completion_callback_.is_null());
82 EXPECT_FALSE(async_connection_->connect_completion_handler_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -070083 }
84
85 void StartConnection() {
86 EXPECT_CALL(sockets_, Socket(_, _, _))
87 .WillOnce(Return(kSocketFD));
88 EXPECT_CALL(sockets_, SetNonBlocking(kSocketFD))
89 .WillOnce(Return(0));
90 EXPECT_CALL(sockets_, BindToDevice(kSocketFD, StrEq(kInterfaceName)))
91 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050092 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
93 .WillOnce(Return(-1));
94 EXPECT_CALL(sockets_, Error())
Paul Stewartf65320c2011-10-13 14:34:52 -070095 .WillOnce(Return(EINPROGRESS));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050096 EXPECT_CALL(dispatcher(),
97 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -070098 .WillOnce(ReturnNew<IOHandler>());
99 EXPECT_TRUE(async_connection().Start(address_, kConnectPort));
100 }
101
102 void OnConnectCompletion(int fd) {
Paul Stewart8585b202012-09-21 14:03:01 -0700103 async_connection_->OnConnectCompletion(fd);
Paul Stewartf65320c2011-10-13 14:34:52 -0700104 }
Paul Stewart8585b202012-09-21 14:03:01 -0700105 AsyncConnection &async_connection() { return *async_connection_.get(); }
Paul Stewartf65320c2011-10-13 14:34:52 -0700106 StrictMock<MockSockets> &sockets() { return sockets_; }
107 MockEventDispatcher &dispatcher() { return dispatcher_; }
108 const IPAddress &address() { return address_; }
Paul Stewart8585b202012-09-21 14:03:01 -0700109 int fd() { return async_connection_->fd_; }
110 void set_fd(int fd) { async_connection_->fd_ = fd; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700111 StrictMock<ConnectCallbackTarget> &callback_target() {
112 return callback_target_;
113 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700114
115 private:
116 MockEventDispatcher dispatcher_;
117 StrictMock<MockSockets> sockets_;
118 StrictMock<ConnectCallbackTarget> callback_target_;
Paul Stewart8585b202012-09-21 14:03:01 -0700119 scoped_ptr<AsyncConnection> async_connection_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700120 IPAddress address_;
121};
122
123TEST_F(AsyncConnectionTest, InitState) {
124 ExpectReset();
125 EXPECT_EQ(string(), async_connection().error());
126}
127
128TEST_F(AsyncConnectionTest, StartSocketFailure) {
129 EXPECT_CALL(sockets(), Socket(_, _, _))
130 .WillOnce(Return(-1));
131 EXPECT_CALL(sockets(), Error())
132 .WillOnce(Return(kErrorNumber));
133 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
134 ExpectReset();
135 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
136}
137
138TEST_F(AsyncConnectionTest, StartNonBlockingFailure) {
139 EXPECT_CALL(sockets(), Socket(_, _, _))
140 .WillOnce(Return(kSocketFD));
141 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
142 .WillOnce(Return(-1));
143 EXPECT_CALL(sockets(), Error())
144 .WillOnce(Return(kErrorNumber));
145 EXPECT_CALL(sockets(), Close(kSocketFD))
146 .WillOnce(Return(0));
147 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
148 ExpectReset();
149 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
150}
151
152TEST_F(AsyncConnectionTest, StartBindToDeviceFailure) {
153 EXPECT_CALL(sockets(), Socket(_, _, _))
154 .WillOnce(Return(kSocketFD));
155 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
156 .WillOnce(Return(0));
157 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
158 .WillOnce(Return(-1));
159 EXPECT_CALL(sockets(), Error())
160 .WillOnce(Return(kErrorNumber));
161 EXPECT_CALL(sockets(), Close(kSocketFD))
162 .WillOnce(Return(0));
163 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
164 ExpectReset();
165 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
166}
167
168TEST_F(AsyncConnectionTest, SynchronousFailure) {
169 EXPECT_CALL(sockets(), Socket(_, _, _))
170 .WillOnce(Return(kSocketFD));
171 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
172 .WillOnce(Return(0));
173 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
174 .WillOnce(Return(0));
175 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
176 .WillOnce(Return(-1));
177 EXPECT_CALL(sockets(), Error())
178 .Times(2)
179 .WillRepeatedly(Return(0));
180 EXPECT_CALL(sockets(), Close(kSocketFD))
181 .WillOnce(Return(0));
182 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
183 ExpectReset();
184}
185
186MATCHER_P2(IsSocketAddress, address, port, "") {
187 const struct sockaddr_in *arg_saddr =
188 reinterpret_cast<const struct sockaddr_in *>(arg);
189 IPAddress arg_addr(IPAddress::kFamilyIPv4,
190 ByteString(reinterpret_cast<const unsigned char *>(
191 &arg_saddr->sin_addr.s_addr),
192 sizeof(arg_saddr->sin_addr.s_addr)));
193 return address.Equals(arg_addr) && arg_saddr->sin_port == htons(port);
194}
195
196TEST_F(AsyncConnectionTest, SynchronousStart) {
197 EXPECT_CALL(sockets(), Socket(_, _, _))
198 .WillOnce(Return(kSocketFD));
199 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
200 .WillOnce(Return(0));
201 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
202 .WillOnce(Return(0));
203 EXPECT_CALL(sockets(), Connect(kSocketFD,
204 IsSocketAddress(address(), kConnectPort),
205 sizeof(struct sockaddr_in)))
206 .WillOnce(Return(-1));
207 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500208 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700209 .WillOnce(ReturnNew<IOHandler>());
210 EXPECT_CALL(sockets(), Error())
211 .WillOnce(Return(EINPROGRESS));
212 EXPECT_TRUE(async_connection().Start(address(), kConnectPort));
213 EXPECT_EQ(kSocketFD, fd());
214}
215
216TEST_F(AsyncConnectionTest, AsynchronousFailure) {
217 StartConnection();
218 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
219 .WillOnce(Return(1));
220 EXPECT_CALL(sockets(), Error())
221 .WillOnce(Return(kErrorNumber));
222 EXPECT_CALL(callback_target(), CallTarget(false, -1));
223 EXPECT_CALL(sockets(), Close(kSocketFD))
224 .WillOnce(Return(0));
225 OnConnectCompletion(kSocketFD);
226 ExpectReset();
227 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
228}
229
230TEST_F(AsyncConnectionTest, AsynchronousSuccess) {
231 StartConnection();
232 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
233 .WillOnce(Return(0));
234 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
235 OnConnectCompletion(kSocketFD);
236 ExpectReset();
237}
238
239TEST_F(AsyncConnectionTest, SynchronousSuccess) {
240 EXPECT_CALL(sockets(), Socket(_, _, _))
241 .WillOnce(Return(kSocketFD));
242 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
243 .WillOnce(Return(0));
244 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
245 .WillOnce(Return(0));
246 EXPECT_CALL(sockets(), Connect(kSocketFD,
247 IsSocketAddress(address(), kConnectPort),
248 sizeof(struct sockaddr_in)))
249 .WillOnce(Return(0));
250 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
251 EXPECT_TRUE(async_connection().Start(address(), kConnectPort));
252 ExpectReset();
253}
254
Paul Stewart8585b202012-09-21 14:03:01 -0700255TEST_F(AsyncConnectionTest, FreeOnSuccessCallback) {
256 StartConnection();
257 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
258 .WillOnce(Return(0));
259 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD))
260 .WillOnce(Invoke(this, &AsyncConnectionTest::InvokeFreeConnection));
261 OnConnectCompletion(kSocketFD);
262}
263
264TEST_F(AsyncConnectionTest, FreeOnFailureCallback) {
265 StartConnection();
266 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
267 .WillOnce(Return(1));
268 EXPECT_CALL(callback_target(), CallTarget(false, -1))
269 .WillOnce(Invoke(this, &AsyncConnectionTest::InvokeFreeConnection));
270 EXPECT_CALL(sockets(), Error())
271 .WillOnce(Return(kErrorNumber));
272 EXPECT_CALL(sockets(), Close(kSocketFD))
273 .WillOnce(Return(0));
274 OnConnectCompletion(kSocketFD);
275}
276
Paul Stewartf65320c2011-10-13 14:34:52 -0700277} // namespace shill