blob: d29fcd65cecc8b3dc116c1b8c63042145cea96f2 [file] [log] [blame]
Paul Stewart188a84a2012-01-20 16:28:15 -08001// Copyright (c) 2012 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/http_request.h"
6
7#include <netinet/in.h>
8
9#include <string>
10#include <vector>
11
12#include <base/stringprintf.h>
13#include <gtest/gtest.h>
14
15#include "shill/ip_address.h"
16#include "shill/http_url.h"
17#include "shill/mock_async_connection.h"
18#include "shill/mock_connection.h"
19#include "shill/mock_control.h"
20#include "shill/mock_device_info.h"
21#include "shill/mock_dns_client.h"
22#include "shill/mock_event_dispatcher.h"
23#include "shill/mock_sockets.h"
24
25using base::StringPrintf;
26using std::string;
27using std::vector;
28using ::testing::_;
29using ::testing::AtLeast;
30using ::testing::DoAll;
31using ::testing::Invoke;
32using ::testing::NiceMock;
33using ::testing::Return;
34using ::testing::ReturnArg;
35using ::testing::ReturnNew;
36using ::testing::ReturnRef;
37using ::testing::SetArgumentPointee;
38using ::testing::StrEq;
39using ::testing::StrictMock;
40using ::testing::Test;
41
42namespace shill {
43
44namespace {
45const char kTextSiteName[] = "www.chromium.org";
46const char kTextURL[] = "http://www.chromium.org/path/to/resource";
47const char kNumericURL[] = "http://10.1.1.1";
48const char kPath[] = "/path/to/resource";
49const char kBadURL[] = "xxx";
50const char kInterfaceName[] = "int0";
51const char kDNSServer0[] = "8.8.8.8";
52const char kDNSServer1[] = "8.8.4.4";
53const char *kDNSServers[] = { kDNSServer0, kDNSServer1 };
54const char kServerAddress[] = "10.1.1.1";
55const int kServerFD = 10203;
56const int kServerPort = 80;
57} // namespace {}
58
59MATCHER_P(IsIPAddress, address, "") {
60 IPAddress ip_address(IPAddress::kFamilyIPv4);
61 EXPECT_TRUE(ip_address.SetAddressFromString(address));
62 return ip_address.Equals(arg);
63}
64
65class HTTPRequestTest : public Test {
66 public:
67 HTTPRequestTest()
68 : interface_name_(kInterfaceName),
69 server_async_connection_(new StrictMock<MockAsyncConnection>()),
70 dns_servers_(kDNSServers, kDNSServers + 2),
71 dns_client_(new StrictMock<MockDNSClient>()),
72 device_info_(new NiceMock<MockDeviceInfo>(
73 &control_,
74 reinterpret_cast<EventDispatcher*>(NULL),
75 reinterpret_cast<Metrics*>(NULL),
76 reinterpret_cast<Manager*>(NULL))),
77 connection_(new StrictMock<MockConnection>(device_info_.get())) { }
78 protected:
79 class CallbackTarget {
80 public:
81 CallbackTarget()
82 : read_event_callback_(
83 NewCallback(this, &CallbackTarget::ReadEventCallTarget)),
84 result_callback_(
85 NewCallback(this, &CallbackTarget::ResultCallTarget)) {}
86
87 MOCK_METHOD1(ReadEventCallTarget, void(int byte_count));
88 MOCK_METHOD1(ResultCallTarget, void(HTTPRequest::Result));
89 Callback1<int>::Type *read_event_callback() {
90 return read_event_callback_.get();
91 }
92 Callback1<HTTPRequest::Result>::Type *result_callback() {
93 return result_callback_.get();
94 }
95
96 private:
97 scoped_ptr<Callback1<int>::Type> read_event_callback_;
98 scoped_ptr<Callback1<HTTPRequest::Result>::Type> result_callback_;
99 };
100
101 virtual void SetUp() {
102 EXPECT_CALL(*connection_.get(), interface_name())
103 .WillRepeatedly(ReturnRef(interface_name_));
104 EXPECT_CALL(*connection_.get(), dns_servers())
105 .WillRepeatedly(ReturnRef(dns_servers_));
106
107 request_.reset(new HTTPRequest(connection_, &dispatcher_, &sockets_));
108 // Passes ownership.
109 request_->dns_client_.reset(dns_client_);
110 // Passes ownership.
111 request_->server_async_connection_.reset(server_async_connection_);
112 }
113 virtual void TearDown() {
114 if (request_->is_running_) {
115 ExpectStop();
116
117 // Subtle: Make sure the finalization of the request happens while our
118 // expectations are still active.
119 request_.reset();
120 }
121 }
122 size_t FindInRequestData(const string &find_string) {
123 string request_string(
124 reinterpret_cast<char *>(request_->request_data_.GetData()),
125 request_->request_data_.GetLength());
126 return request_string.find(find_string);
127 }
128 // Accessors
129 const ByteString &GetRequestData() {
130 return request_->request_data_;
131 }
132 HTTPRequest *request() { return request_.get(); }
133 MockSockets &sockets() { return sockets_; }
134
135 // Expectations
136 void ExpectReset() {
137 EXPECT_EQ(connection_.get(), request_->connection_.get());
138 EXPECT_EQ(&dispatcher_, request_->dispatcher_);
139 EXPECT_EQ(&sockets_, request_->sockets_);
140 EXPECT_FALSE(request_->result_callback_);
141 EXPECT_FALSE(request_->read_event_callback_);
142 EXPECT_TRUE(request_->task_factory_.empty());
143 EXPECT_FALSE(request_->idle_timeout_);
144 EXPECT_FALSE(request_->read_server_handler_.get());
145 EXPECT_FALSE(request_->write_server_handler_.get());
146 EXPECT_EQ(dns_client_, request_->dns_client_.get());
147 EXPECT_EQ(server_async_connection_,
148 request_->server_async_connection_.get());
149 EXPECT_TRUE(request_->server_hostname_.empty());
150 EXPECT_EQ(-1, request_->server_port_);
151 EXPECT_EQ(-1, request_->server_socket_);
152 EXPECT_EQ(HTTPRequest::kResultUnknown, request_->timeout_result_);
153 EXPECT_TRUE(request_->request_data_.IsEmpty());
154 EXPECT_TRUE(request_->response_data_.IsEmpty());
155 EXPECT_FALSE(request_->is_running_);
156 }
157 void ExpectStop() {
158 if (request_->server_socket_ != -1) {
159 EXPECT_CALL(sockets(), Close(kServerFD))
160 .WillOnce(Return(0));
161 }
162 EXPECT_CALL(*dns_client_, Stop())
163 .Times(AtLeast(1));
164 EXPECT_CALL(*server_async_connection_, Stop())
165 .Times(AtLeast(1));
166 EXPECT_CALL(*connection_.get(), ReleaseRouting());
167 }
168 void ExpectSetTimeout(int timeout) {
169 EXPECT_CALL(dispatcher_, PostDelayedTask(_, timeout * 1000))
170 .WillOnce(Return(true));
171 }
172 void ExpectSetConnectTimeout() {
173 ExpectSetTimeout(HTTPRequest::kConnectTimeoutSeconds);
174 }
175 void ExpectSetInputTimeout() {
176 ExpectSetTimeout(HTTPRequest::kInputTimeoutSeconds);
177 }
178 void ExpectInResponse(const string &expected_response_data) {
179 string response_string(
180 reinterpret_cast<char *>(request_->response_data_.GetData()),
181 request_->response_data_.GetLength());
182 EXPECT_NE(string::npos, response_string.find(expected_response_data));
183 }
184 void ExpectDNSRequest(const string &host, bool return_value) {
185 EXPECT_CALL(*dns_client_, Start(StrEq(host)))
186 .WillOnce(Return(return_value));
187 }
188 void ExpectDNSFailure(const string &error) {
189 EXPECT_CALL(*dns_client_, error())
190 .WillOnce(ReturnRef(error));
191 }
192 void ExpectAsyncConnect(const string &address, int port,
193 bool return_value) {
194 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
195 .WillOnce(Return(return_value));
196 if (return_value) {
197 ExpectSetConnectTimeout();
198 }
199 }
200 void InvokeSyncConnect(const IPAddress &/*address*/, int /*port*/) {
201 CallConnectCompletion(true, kServerFD);
202 }
203 void CallConnectCompletion(bool success, int fd) {
204 request_->OnConnectCompletion(success, fd);
205 }
206 void ExpectSyncConnect(const string &address, int port) {
207 EXPECT_CALL(*server_async_connection_, Start(IsIPAddress(address), port))
208 .WillOnce(DoAll(Invoke(this, &HTTPRequestTest::InvokeSyncConnect),
209 Return(true)));
210 }
211 void ExpectConnectFailure() {
212 EXPECT_CALL(*server_async_connection_, Start(_, _))
213 .WillOnce(Return(false));
214 }
215 void ExpectMonitorServerInput() {
216 EXPECT_CALL(dispatcher_,
217 CreateInputHandler(kServerFD,
218 request_->read_server_callback_.get()))
219 .WillOnce(ReturnNew<IOHandler>());
220 ExpectSetInputTimeout();
221 }
222 void ExpectMonitorServerOutput() {
223 EXPECT_CALL(dispatcher_,
224 CreateReadyHandler(kServerFD,
225 IOHandler::kModeOutput,
226 request_->write_server_callback_.get()))
227 .WillOnce(ReturnNew<IOHandler>());
228 ExpectSetInputTimeout();
229 }
230 void ExpectRouteRequest() {
231 EXPECT_CALL(*connection_.get(), RequestRouting());
232 }
233 void ExpectRouteRelease() {
234 EXPECT_CALL(*connection_.get(), ReleaseRouting());
235 }
236 void ExpectResultCallback(HTTPRequest::Result result) {
237 EXPECT_CALL(target_, ResultCallTarget(result));
238 }
239 void InvokeResultVerify(HTTPRequest::Result result) {
240 EXPECT_EQ(HTTPRequest::kResultSuccess, result);
241 EXPECT_TRUE(expected_response_.Equals(request_->response_data()));
242 }
243 void ExpectResultCallbackWithResponse(const string &response) {
244 expected_response_ = ByteString(response, false);
245 EXPECT_CALL(target_, ResultCallTarget(HTTPRequest::kResultSuccess))
246 .WillOnce(Invoke(this, &HTTPRequestTest::InvokeResultVerify));
247 }
248 void ExpectReadEventCallback(int byte_count) {
249 EXPECT_CALL(target_, ReadEventCallTarget(byte_count));
250 }
251 void GetDNSResult(bool result) {
252 request_->GetDNSResult(result);
253 }
254 void OnConnectCompletion(bool result, int sockfd) {
255 request_->OnConnectCompletion(result, sockfd);
256 }
257 void ReadFromServer(const string &data) {
258 const unsigned char *ptr =
259 reinterpret_cast<const unsigned char *>(data.c_str());
260 vector<unsigned char> data_writable(ptr, ptr + data.length());
261 InputData server_data(data_writable.data(), data_writable.size());
262 request_->ReadFromServer(&server_data);
263 }
264 void WriteToServer(int fd) {
265 request_->WriteToServer(fd);
266 }
267 HTTPRequest::Result StartRequest(const string &url) {
268 HTTPURL http_url;
269 EXPECT_TRUE(http_url.ParseFromString(url));
270 return request_->Start(http_url,
271 target_.read_event_callback(),
272 target_.result_callback());
273 }
274 void SetupConnectWithURL(const string &url, const string &expected_hostname) {
275 ExpectRouteRequest();
276 ExpectDNSRequest(expected_hostname, true);
277 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(url));
278 IPAddress addr(IPAddress::kFamilyIPv4);
279 EXPECT_TRUE(addr.SetAddressFromString(kServerAddress));
280 EXPECT_CALL(*dns_client_, address())
281 .WillOnce(ReturnRef(addr));;
282 GetDNSResult(true);
283 }
284 void SetupConnect() {
285 SetupConnectWithURL(kTextURL, kTextSiteName);
286 }
287 void SetupConnectAsync() {
288 ExpectAsyncConnect(kServerAddress, kServerPort, true);
289 SetupConnect();
290 }
291 void SetupConnectComplete() {
292 SetupConnectAsync();
293 ExpectMonitorServerOutput();
294 OnConnectCompletion(true, kServerFD);
295 }
296 void CallTimeoutTask() {
297 request_->TimeoutTask();
298 }
299
300 private:
301 const string interface_name_;
302 // Owned by the HTTPRequest, but tracked here for EXPECT().
303 StrictMock<MockAsyncConnection> *server_async_connection_;
304 vector<string> dns_servers_;
305 // Owned by the HTTPRequest, but tracked here for EXPECT().
306 StrictMock<MockDNSClient> *dns_client_;
307 StrictMock<MockEventDispatcher> dispatcher_;
308 MockControl control_;
309 scoped_ptr<MockDeviceInfo> device_info_;
310 scoped_refptr<MockConnection> connection_;
311 scoped_ptr<HTTPRequest> request_;
312 StrictMock<MockSockets> sockets_;
313 StrictMock<CallbackTarget> target_;
314 ByteString expected_response_;
315};
316
317TEST_F(HTTPRequestTest, Constructor) {
318 ExpectReset();
319}
320
321
322TEST_F(HTTPRequestTest, FailConnectNumericSynchronous) {
323 ExpectRouteRequest();
324 ExpectConnectFailure();
325 ExpectStop();
326 EXPECT_EQ(HTTPRequest::kResultConnectionFailure, StartRequest(kNumericURL));
327 ExpectReset();
328}
329
330TEST_F(HTTPRequestTest, FailConnectNumericAsynchronous) {
331 ExpectRouteRequest();
332 ExpectAsyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort, true);
333 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
334 ExpectResultCallback(HTTPRequest::kResultConnectionFailure);
335 ExpectStop();
336 CallConnectCompletion(false, -1);
337 ExpectReset();
338}
339
340TEST_F(HTTPRequestTest, FailConnectNumericTimeout) {
341 ExpectRouteRequest();
342 ExpectAsyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort, true);
343 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
344 ExpectResultCallback(HTTPRequest::kResultConnectionTimeout);
345 ExpectStop();
346 CallTimeoutTask();
347 ExpectReset();
348}
349
350TEST_F(HTTPRequestTest, SyncConnectNumeric) {
351 ExpectRouteRequest();
352 ExpectSyncConnect(kServerAddress, HTTPURL::kDefaultHTTPPort);
353 ExpectMonitorServerOutput();
354 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kNumericURL));
355}
356
357TEST_F(HTTPRequestTest, FailDNSStart) {
358 ExpectRouteRequest();
359 ExpectDNSRequest(kTextSiteName, false);
360 ExpectStop();
361 EXPECT_EQ(HTTPRequest::kResultDNSFailure, StartRequest(kTextURL));
362 ExpectReset();
363}
364
365TEST_F(HTTPRequestTest, FailDNSFailure) {
366 ExpectRouteRequest();
367 ExpectDNSRequest(kTextSiteName, true);
368 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kTextURL));
369 const string error(DNSClient::kErrorNoData);
370 ExpectDNSFailure(error);
371 ExpectResultCallback(HTTPRequest::kResultDNSFailure);
372 ExpectStop();
373 GetDNSResult(false);
374 ExpectReset();
375}
376
377TEST_F(HTTPRequestTest, FailDNSTimeout) {
378 ExpectRouteRequest();
379 ExpectDNSRequest(kTextSiteName, true);
380 EXPECT_EQ(HTTPRequest::kResultInProgress, StartRequest(kTextURL));
381 const string error(DNSClient::kErrorTimedOut);
382 ExpectDNSFailure(error);
383 ExpectResultCallback(HTTPRequest::kResultDNSTimeout);
384 ExpectStop();
385 GetDNSResult(false);
386 ExpectReset();
387}
388
389TEST_F(HTTPRequestTest, FailConnectText) {
390 ExpectConnectFailure();
391 ExpectResultCallback(HTTPRequest::kResultConnectionFailure);
392 ExpectStop();
393 SetupConnect();
394 ExpectReset();
395}
396
397TEST_F(HTTPRequestTest, ConnectComplete) {
398 SetupConnectComplete();
399}
400
401TEST_F(HTTPRequestTest, RequestTimeout) {
402 SetupConnectComplete();
403 ExpectResultCallback(HTTPRequest::kResultRequestTimeout);
404 ExpectStop();
405 CallTimeoutTask();
406}
407
408TEST_F(HTTPRequestTest, RequestData) {
409 SetupConnectComplete();
410 EXPECT_EQ(0, FindInRequestData(string("GET ") + kPath));
411 EXPECT_NE(string::npos,
412 FindInRequestData(string("\r\nHost: ") + kTextSiteName));
413 ByteString request_data = GetRequestData();
414 EXPECT_CALL(sockets(), Send(kServerFD, _, request_data.GetLength(), 0))
415 .WillOnce(Return(request_data.GetLength() - 1));
416 ExpectSetInputTimeout();
417 WriteToServer(kServerFD);
418 EXPECT_CALL(sockets(), Send(kServerFD, _, 1, 0))
419 .WillOnce(Return(1));
420 ExpectMonitorServerInput();
421 WriteToServer(kServerFD);
422}
423
424TEST_F(HTTPRequestTest, ResponseTimeout) {
425 SetupConnectComplete();
426 ByteString request_data = GetRequestData();
427 EXPECT_CALL(sockets(), Send(kServerFD, _, request_data.GetLength(), 0))
428 .WillOnce(Return(request_data.GetLength()));
429 ExpectMonitorServerInput();
430 WriteToServer(kServerFD);
431 ExpectResultCallback(HTTPRequest::kResultResponseTimeout);
432 ExpectStop();
433 CallTimeoutTask();
434}
435
436TEST_F(HTTPRequestTest, ResponseData) {
437 SetupConnectComplete();
438 const string response0("hello");
439 ExpectReadEventCallback(response0.length());
440 ExpectSetInputTimeout();
441 ReadFromServer(response0);
442 ExpectInResponse(response0);
443
444 const string response1(" to you");
445 ExpectReadEventCallback(response1.length());
446 ExpectSetInputTimeout();
447 ReadFromServer(response1);
448 ExpectInResponse(response1);
449
450 ExpectResultCallbackWithResponse(response0 + response1);
451 ExpectStop();
452 ReadFromServer("");
453}
454
455} // namespace shill