blob: ee9a41e8632719f05cd46f5731566d3f5318e081 [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()
42 : async_connection_(kInterfaceName, &dispatcher_, &sockets_,
43 callback_target_.callback()),
44 address_(IPAddress::kFamilyIPv4) { }
45
46 virtual void SetUp() {
47 EXPECT_TRUE(address_.SetAddressFromString(kConnectAddress));
48 }
49 virtual void TearDown() {
50 if (async_connection_.fd_ >= 0) {
51 EXPECT_CALL(sockets(), Close(kSocketFD))
52 .WillOnce(Return(0));
53 }
54 }
55
56 protected:
57 class ConnectCallbackTarget {
58 public:
59 ConnectCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -050060 : callback_(Bind(&ConnectCallbackTarget::CallTarget,
61 Unretained(this))) {}
Paul Stewartf65320c2011-10-13 14:34:52 -070062
63 MOCK_METHOD2(CallTarget, void(bool success, int fd));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050064 const Callback<void(bool, int)> &callback() { return callback_; }
Paul Stewartf65320c2011-10-13 14:34:52 -070065
66 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -050067 Callback<void(bool, int)> callback_;
Paul Stewartf65320c2011-10-13 14:34:52 -070068 };
69
70 void ExpectReset() {
71 EXPECT_STREQ(kInterfaceName, async_connection_.interface_name_.c_str());
72 EXPECT_EQ(&dispatcher_, async_connection_.dispatcher_);
73 EXPECT_EQ(&sockets_, async_connection_.sockets_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050074 EXPECT_TRUE(callback_target_.callback().
75 Equals(async_connection_.callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -070076 EXPECT_EQ(-1, async_connection_.fd_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050077 EXPECT_FALSE(async_connection_.connect_completion_callback_.is_null());
Paul Stewartf65320c2011-10-13 14:34:52 -070078 EXPECT_FALSE(async_connection_.connect_completion_handler_.get());
79 }
80
81 void StartConnection() {
82 EXPECT_CALL(sockets_, Socket(_, _, _))
83 .WillOnce(Return(kSocketFD));
84 EXPECT_CALL(sockets_, SetNonBlocking(kSocketFD))
85 .WillOnce(Return(0));
86 EXPECT_CALL(sockets_, BindToDevice(kSocketFD, StrEq(kInterfaceName)))
87 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050088 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
89 .WillOnce(Return(-1));
90 EXPECT_CALL(sockets_, Error())
Paul Stewartf65320c2011-10-13 14:34:52 -070091 .WillOnce(Return(EINPROGRESS));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050092 EXPECT_CALL(dispatcher(),
93 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -070094 .WillOnce(ReturnNew<IOHandler>());
95 EXPECT_TRUE(async_connection().Start(address_, kConnectPort));
96 }
97
98 void OnConnectCompletion(int fd) {
99 async_connection_.OnConnectCompletion(fd);
100 }
101 AsyncConnection &async_connection() { return async_connection_; }
102 StrictMock<MockSockets> &sockets() { return sockets_; }
103 MockEventDispatcher &dispatcher() { return dispatcher_; }
104 const IPAddress &address() { return address_; }
105 int fd() { return async_connection_.fd_; }
106 void set_fd(int fd) { async_connection_.fd_ = fd; }
107 StrictMock<ConnectCallbackTarget> &callback_target() {
108 return callback_target_;
109 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700110
111 private:
112 MockEventDispatcher dispatcher_;
113 StrictMock<MockSockets> sockets_;
114 StrictMock<ConnectCallbackTarget> callback_target_;
115 AsyncConnection async_connection_;
116 IPAddress address_;
117};
118
119TEST_F(AsyncConnectionTest, InitState) {
120 ExpectReset();
121 EXPECT_EQ(string(), async_connection().error());
122}
123
124TEST_F(AsyncConnectionTest, StartSocketFailure) {
125 EXPECT_CALL(sockets(), Socket(_, _, _))
126 .WillOnce(Return(-1));
127 EXPECT_CALL(sockets(), Error())
128 .WillOnce(Return(kErrorNumber));
129 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
130 ExpectReset();
131 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
132}
133
134TEST_F(AsyncConnectionTest, StartNonBlockingFailure) {
135 EXPECT_CALL(sockets(), Socket(_, _, _))
136 .WillOnce(Return(kSocketFD));
137 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
138 .WillOnce(Return(-1));
139 EXPECT_CALL(sockets(), Error())
140 .WillOnce(Return(kErrorNumber));
141 EXPECT_CALL(sockets(), Close(kSocketFD))
142 .WillOnce(Return(0));
143 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
144 ExpectReset();
145 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
146}
147
148TEST_F(AsyncConnectionTest, StartBindToDeviceFailure) {
149 EXPECT_CALL(sockets(), Socket(_, _, _))
150 .WillOnce(Return(kSocketFD));
151 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
152 .WillOnce(Return(0));
153 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
154 .WillOnce(Return(-1));
155 EXPECT_CALL(sockets(), Error())
156 .WillOnce(Return(kErrorNumber));
157 EXPECT_CALL(sockets(), Close(kSocketFD))
158 .WillOnce(Return(0));
159 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
160 ExpectReset();
161 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
162}
163
164TEST_F(AsyncConnectionTest, SynchronousFailure) {
165 EXPECT_CALL(sockets(), Socket(_, _, _))
166 .WillOnce(Return(kSocketFD));
167 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
168 .WillOnce(Return(0));
169 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
170 .WillOnce(Return(0));
171 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
172 .WillOnce(Return(-1));
173 EXPECT_CALL(sockets(), Error())
174 .Times(2)
175 .WillRepeatedly(Return(0));
176 EXPECT_CALL(sockets(), Close(kSocketFD))
177 .WillOnce(Return(0));
178 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
179 ExpectReset();
180}
181
182MATCHER_P2(IsSocketAddress, address, port, "") {
183 const struct sockaddr_in *arg_saddr =
184 reinterpret_cast<const struct sockaddr_in *>(arg);
185 IPAddress arg_addr(IPAddress::kFamilyIPv4,
186 ByteString(reinterpret_cast<const unsigned char *>(
187 &arg_saddr->sin_addr.s_addr),
188 sizeof(arg_saddr->sin_addr.s_addr)));
189 return address.Equals(arg_addr) && arg_saddr->sin_port == htons(port);
190}
191
192TEST_F(AsyncConnectionTest, SynchronousStart) {
193 EXPECT_CALL(sockets(), Socket(_, _, _))
194 .WillOnce(Return(kSocketFD));
195 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
196 .WillOnce(Return(0));
197 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
198 .WillOnce(Return(0));
199 EXPECT_CALL(sockets(), Connect(kSocketFD,
200 IsSocketAddress(address(), kConnectPort),
201 sizeof(struct sockaddr_in)))
202 .WillOnce(Return(-1));
203 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500204 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700205 .WillOnce(ReturnNew<IOHandler>());
206 EXPECT_CALL(sockets(), Error())
207 .WillOnce(Return(EINPROGRESS));
208 EXPECT_TRUE(async_connection().Start(address(), kConnectPort));
209 EXPECT_EQ(kSocketFD, fd());
210}
211
212TEST_F(AsyncConnectionTest, AsynchronousFailure) {
213 StartConnection();
214 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
215 .WillOnce(Return(1));
216 EXPECT_CALL(sockets(), Error())
217 .WillOnce(Return(kErrorNumber));
218 EXPECT_CALL(callback_target(), CallTarget(false, -1));
219 EXPECT_CALL(sockets(), Close(kSocketFD))
220 .WillOnce(Return(0));
221 OnConnectCompletion(kSocketFD);
222 ExpectReset();
223 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
224}
225
226TEST_F(AsyncConnectionTest, AsynchronousSuccess) {
227 StartConnection();
228 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
229 .WillOnce(Return(0));
230 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
231 OnConnectCompletion(kSocketFD);
232 ExpectReset();
233}
234
235TEST_F(AsyncConnectionTest, SynchronousSuccess) {
236 EXPECT_CALL(sockets(), Socket(_, _, _))
237 .WillOnce(Return(kSocketFD));
238 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
239 .WillOnce(Return(0));
240 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
241 .WillOnce(Return(0));
242 EXPECT_CALL(sockets(), Connect(kSocketFD,
243 IsSocketAddress(address(), kConnectPort),
244 sizeof(struct sockaddr_in)))
245 .WillOnce(Return(0));
246 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
247 EXPECT_TRUE(async_connection().Start(address(), kConnectPort));
248 ExpectReset();
249}
250
251} // namespace shill