blob: b78781d3be3c6a7759248a58ce73f54de7e4b524 [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
11#include <gtest/gtest.h>
12
13#include "shill/ip_address.h"
14#include "shill/mock_event_dispatcher.h"
15#include "shill/mock_sockets.h"
16
17using std::string;
18using ::testing::_;
19using ::testing::Return;
20using ::testing::ReturnNew;
21using ::testing::StrEq;
22using ::testing::StrictMock;
23using ::testing::Test;
24
25namespace shill {
26
27namespace {
28const char kInterfaceName[] = "int0";
29const char kConnectAddress[] = "10.11.12.13";
30const int kConnectPort = 10203;
31const int kErrorNumber = 30405;
32const int kSocketFD = 60708;
33} // namespace {}
34
35class AsyncConnectionTest : public Test {
36 public:
37 AsyncConnectionTest()
38 : async_connection_(kInterfaceName, &dispatcher_, &sockets_,
39 callback_target_.callback()),
40 address_(IPAddress::kFamilyIPv4) { }
41
42 virtual void SetUp() {
43 EXPECT_TRUE(address_.SetAddressFromString(kConnectAddress));
44 }
45 virtual void TearDown() {
46 if (async_connection_.fd_ >= 0) {
47 EXPECT_CALL(sockets(), Close(kSocketFD))
48 .WillOnce(Return(0));
49 }
50 }
51
52 protected:
53 class ConnectCallbackTarget {
54 public:
55 ConnectCallbackTarget()
56 : callback_(NewCallback(this, &ConnectCallbackTarget::CallTarget)) {}
57
58 MOCK_METHOD2(CallTarget, void(bool success, int fd));
59 Callback2<bool, int>::Type *callback() { return callback_.get(); }
60
61 private:
62 scoped_ptr<Callback2<bool, int>::Type> callback_;
63 };
64
65 void ExpectReset() {
66 EXPECT_STREQ(kInterfaceName, async_connection_.interface_name_.c_str());
67 EXPECT_EQ(&dispatcher_, async_connection_.dispatcher_);
68 EXPECT_EQ(&sockets_, async_connection_.sockets_);
69 EXPECT_EQ(callback_target_.callback(), async_connection_.callback_);
70 EXPECT_EQ(-1, async_connection_.fd_);
71 EXPECT_TRUE(async_connection_.connect_completion_callback_.get());
72 EXPECT_FALSE(async_connection_.connect_completion_handler_.get());
73 }
74
75 void StartConnection() {
76 EXPECT_CALL(sockets_, Socket(_, _, _))
77 .WillOnce(Return(kSocketFD));
78 EXPECT_CALL(sockets_, SetNonBlocking(kSocketFD))
79 .WillOnce(Return(0));
80 EXPECT_CALL(sockets_, BindToDevice(kSocketFD, StrEq(kInterfaceName)))
81 .WillOnce(Return(0));
82 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
83 .WillOnce(Return(-1));
84 EXPECT_CALL(sockets_, Error())
85 .WillOnce(Return(EINPROGRESS));
86 EXPECT_CALL(dispatcher(), CreateReadyHandler(kSocketFD,
87 IOHandler::kModeOutput,
88 connect_completion_callback()))
89 .WillOnce(ReturnNew<IOHandler>());
90 EXPECT_TRUE(async_connection().Start(address_, kConnectPort));
91 }
92
93 void OnConnectCompletion(int fd) {
94 async_connection_.OnConnectCompletion(fd);
95 }
96 AsyncConnection &async_connection() { return async_connection_; }
97 StrictMock<MockSockets> &sockets() { return sockets_; }
98 MockEventDispatcher &dispatcher() { return dispatcher_; }
99 const IPAddress &address() { return address_; }
100 int fd() { return async_connection_.fd_; }
101 void set_fd(int fd) { async_connection_.fd_ = fd; }
102 StrictMock<ConnectCallbackTarget> &callback_target() {
103 return callback_target_;
104 }
105 Callback1<int>::Type *connect_completion_callback() {
106 return async_connection_.connect_completion_callback_.get();
107 }
108
109 private:
110 MockEventDispatcher dispatcher_;
111 StrictMock<MockSockets> sockets_;
112 StrictMock<ConnectCallbackTarget> callback_target_;
113 AsyncConnection async_connection_;
114 IPAddress address_;
115};
116
117TEST_F(AsyncConnectionTest, InitState) {
118 ExpectReset();
119 EXPECT_EQ(string(), async_connection().error());
120}
121
122TEST_F(AsyncConnectionTest, StartSocketFailure) {
123 EXPECT_CALL(sockets(), Socket(_, _, _))
124 .WillOnce(Return(-1));
125 EXPECT_CALL(sockets(), Error())
126 .WillOnce(Return(kErrorNumber));
127 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
128 ExpectReset();
129 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
130}
131
132TEST_F(AsyncConnectionTest, StartNonBlockingFailure) {
133 EXPECT_CALL(sockets(), Socket(_, _, _))
134 .WillOnce(Return(kSocketFD));
135 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
136 .WillOnce(Return(-1));
137 EXPECT_CALL(sockets(), Error())
138 .WillOnce(Return(kErrorNumber));
139 EXPECT_CALL(sockets(), Close(kSocketFD))
140 .WillOnce(Return(0));
141 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
142 ExpectReset();
143 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
144}
145
146TEST_F(AsyncConnectionTest, StartBindToDeviceFailure) {
147 EXPECT_CALL(sockets(), Socket(_, _, _))
148 .WillOnce(Return(kSocketFD));
149 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
150 .WillOnce(Return(0));
151 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
152 .WillOnce(Return(-1));
153 EXPECT_CALL(sockets(), Error())
154 .WillOnce(Return(kErrorNumber));
155 EXPECT_CALL(sockets(), Close(kSocketFD))
156 .WillOnce(Return(0));
157 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
158 ExpectReset();
159 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
160}
161
162TEST_F(AsyncConnectionTest, SynchronousFailure) {
163 EXPECT_CALL(sockets(), Socket(_, _, _))
164 .WillOnce(Return(kSocketFD));
165 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
166 .WillOnce(Return(0));
167 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
168 .WillOnce(Return(0));
169 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
170 .WillOnce(Return(-1));
171 EXPECT_CALL(sockets(), Error())
172 .Times(2)
173 .WillRepeatedly(Return(0));
174 EXPECT_CALL(sockets(), Close(kSocketFD))
175 .WillOnce(Return(0));
176 EXPECT_FALSE(async_connection().Start(address(), kConnectPort));
177 ExpectReset();
178}
179
180MATCHER_P2(IsSocketAddress, address, port, "") {
181 const struct sockaddr_in *arg_saddr =
182 reinterpret_cast<const struct sockaddr_in *>(arg);
183 IPAddress arg_addr(IPAddress::kFamilyIPv4,
184 ByteString(reinterpret_cast<const unsigned char *>(
185 &arg_saddr->sin_addr.s_addr),
186 sizeof(arg_saddr->sin_addr.s_addr)));
187 return address.Equals(arg_addr) && arg_saddr->sin_port == htons(port);
188}
189
190TEST_F(AsyncConnectionTest, SynchronousStart) {
191 EXPECT_CALL(sockets(), Socket(_, _, _))
192 .WillOnce(Return(kSocketFD));
193 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
194 .WillOnce(Return(0));
195 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
196 .WillOnce(Return(0));
197 EXPECT_CALL(sockets(), Connect(kSocketFD,
198 IsSocketAddress(address(), kConnectPort),
199 sizeof(struct sockaddr_in)))
200 .WillOnce(Return(-1));
201 EXPECT_CALL(dispatcher(),
202 CreateReadyHandler(kSocketFD,
203 IOHandler::kModeOutput,
204 connect_completion_callback()))
205 .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