blob: 33e87d3ddff8887f440b19599ea37094e2f4655b [file] [log] [blame]
Paul Stewarte6927402012-01-23 16:11:30 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartc2350ee2011-10-19 12:28:40 -07002// 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/dns_client.h"
6
7#include <netdb.h>
8
9#include <string>
10#include <vector>
11
12#include <base/memory/scoped_ptr.h>
13#include <gtest/gtest.h>
14#include <gmock/gmock.h>
15
Paul Stewartbdb02e62012-02-22 16:24:33 -080016#include "shill/error.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070017#include "shill/event_dispatcher.h"
18#include "shill/io_handler.h"
19#include "shill/mock_ares.h"
20#include "shill/mock_control.h"
21#include "shill/mock_event_dispatcher.h"
22#include "shill/mock_time.h"
23
24using std::string;
25using std::vector;
26using testing::_;
27using testing::DoAll;
28using testing::Return;
29using testing::ReturnArg;
30using testing::ReturnNew;
31using testing::Test;
32using testing::SetArgumentPointee;
33using testing::StrEq;
34using testing::StrictMock;
35
36namespace shill {
37
38namespace {
39const char kGoodName[] = "all-systems.mcast.net";
40const char kResult[] = "224.0.0.1";
41const char kGoodServer[] = "8.8.8.8";
42const char kBadServer[] = "10.9xx8.7";
43const char kNetworkInterface[] = "eth0";
44char kReturnAddressList0[] = { 224, 0, 0, 1 };
45char *kReturnAddressList[] = { kReturnAddressList0, NULL };
46char kFakeAresChannelData = 0;
47const ares_channel kAresChannel =
48 reinterpret_cast<ares_channel>(&kFakeAresChannelData);
49const int kAresFd = 10203;
50const int kAresTimeoutMS = 2000; // ARES transaction timeout
51const int kAresWaitMS = 1000; // Time period ARES asks caller to wait
52} // namespace {}
53
Paul Stewartbdb02e62012-02-22 16:24:33 -080054MATCHER_P(IsSuccess, is_success, "") {
55 return is_success == arg.IsSuccess();
56}
57
58MATCHER_P2(IsFailure, failure_type, failure_message, "") {
59 return failure_type == arg.type() && failure_message == arg.message();
60}
61
Paul Stewartc2350ee2011-10-19 12:28:40 -070062class DNSClientTest : public Test {
63 public:
Paul Stewartbdb02e62012-02-22 16:24:33 -080064 DNSClientTest()
65 : ares_result_(ARES_SUCCESS), address_result_(IPAddress::kFamilyUnknown) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070066 time_val_.tv_sec = 0;
67 time_val_.tv_usec = 0;
68 ares_timeout_.tv_sec = kAresWaitMS / 1000;
69 ares_timeout_.tv_usec = (kAresWaitMS % 1000) * 1000;
70 hostent_.h_addrtype = IPAddress::kFamilyIPv4;
71 hostent_.h_length = sizeof(kReturnAddressList0);
72 hostent_.h_addr_list = kReturnAddressList;
73 }
74
75 virtual void SetUp() {
Paul Stewarte6927402012-01-23 16:11:30 -080076 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070077 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
78 SetInActive();
79 }
80
81 virtual void TearDown() {
82 // We need to make sure the dns_client instance releases ares_
83 // before the destructor for DNSClientTest deletes ares_.
84 if (dns_client_.get()) {
85 dns_client_->Stop();
86 }
87 }
88
89 void AdvanceTime(int time_ms) {
90 struct timeval adv_time = { time_ms/1000, (time_ms % 1000) * 1000 };
91 timeradd(&time_val_, &adv_time, &time_val_);
Paul Stewarte6927402012-01-23 16:11:30 -080092 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070093 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
94 }
95
96 void CallReplyCB() {
97 dns_client_->ReceiveDNSReplyCB(dns_client_.get(), ares_result_, 0,
98 &hostent_);
99 }
100
101 void CallDNSRead() {
102 dns_client_->HandleDNSRead(kAresFd);
103 }
104
105 void CallDNSWrite() {
106 dns_client_->HandleDNSWrite(kAresFd);
107 }
108
109 void CallTimeout() {
110 dns_client_->HandleTimeout();
111 }
112
Paul Stewartbdb02e62012-02-22 16:24:33 -0800113 void CallCompletion() {
114 dns_client_->HandleCompletion();
115 }
116
Paul Stewartc2350ee2011-10-19 12:28:40 -0700117 void CreateClient(const vector<string> &dns_servers, int timeout_ms) {
118 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
119 kNetworkInterface,
120 dns_servers,
121 timeout_ms,
122 &dispatcher_,
123 callback_target_.callback()));
124 dns_client_->ares_ = &ares_;
125 dns_client_->time_ = &time_;
126 }
127
128 void SetActive() {
129 // Returns that socket kAresFd is readable.
130 EXPECT_CALL(ares_, GetSock(_, _, _))
131 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kAresFd), Return(1)));
132 EXPECT_CALL(ares_, Timeout(_, _, _))
133 .WillRepeatedly(
134 DoAll(SetArgumentPointee<2>(ares_timeout_), ReturnArg<2>()));
135 }
136
137 void SetInActive() {
138 EXPECT_CALL(ares_, GetSock(_, _, _))
139 .WillRepeatedly(Return(0));
140 EXPECT_CALL(ares_, Timeout(_, _, _))
141 .WillRepeatedly(ReturnArg<1>());
142 }
143
144 void SetupRequest(const string &name, const string &server) {
145 vector<string> dns_servers;
146 dns_servers.push_back(server);
147 CreateClient(dns_servers, kAresTimeoutMS);
148 // These expectations are fulfilled when dns_client_->Start() is called.
149 EXPECT_CALL(ares_, InitOptions(_, _, _))
150 .WillOnce(DoAll(SetArgumentPointee<0>(kAresChannel),
151 Return(ARES_SUCCESS)));
152 EXPECT_CALL(ares_, SetLocalDev(kAresChannel, StrEq(kNetworkInterface)))
153 .Times(1);
154 EXPECT_CALL(ares_, GetHostByName(kAresChannel, StrEq(name), _, _, _));
155 }
156
157 void StartValidRequest() {
158 SetupRequest(kGoodName, kGoodServer);
159 EXPECT_CALL(dispatcher_,
160 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
161 .WillOnce(ReturnNew<IOHandler>());
162 SetActive();
163 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800164 Error error;
165 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
166 EXPECT_TRUE(error.IsSuccess());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700167 EXPECT_CALL(ares_, Destroy(kAresChannel));
168 }
169
170 void TestValidCompletion() {
Paul Stewartc2350ee2011-10-19 12:28:40 -0700171 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
172 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800173 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700174 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800175
176 // Make sure that the address value is correct as held in the DNSClient.
177 ASSERT_TRUE(dns_client_->address_.IsValid());
178 IPAddress ipaddr(dns_client_->address_.family());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700179 ASSERT_TRUE(ipaddr.SetAddressFromString(kResult));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800180 EXPECT_TRUE(ipaddr.Equals(dns_client_->address_));
181
182 // Make sure the callback gets called with a success result, and save
183 // the callback address argument in |address_result_|.
184 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(true), _))
185 .WillOnce(Invoke(this, &DNSClientTest::SaveCallbackArgs));
186 CallCompletion();
187
188 // Make sure the address was successfully passed to the callback.
189 EXPECT_TRUE(ipaddr.Equals(address_result_));
190 EXPECT_TRUE(dns_client_->address_.IsDefault());
191 }
192
193 void SaveCallbackArgs(const Error &error, const IPAddress &address) {
194 error_result_.CopyFrom(error);
195 address_result_ = address;
196 }
197
198 void ExpectPostCompletionTask() {
199 EXPECT_CALL(dispatcher_, PostTask(_));
200 }
201
202 void ExpectReset() {
203 EXPECT_TRUE(dns_client_->address_.family() == IPAddress::kFamilyIPv4);
204 EXPECT_TRUE(dns_client_->address_.IsDefault());
205 EXPECT_TRUE(dns_client_->task_factory_.empty());
206 EXPECT_FALSE(dns_client_->resolver_state_.get());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700207 }
208
209 protected:
210 class DNSCallbackTarget {
211 public:
212 DNSCallbackTarget()
213 : callback_(NewCallback(this, &DNSCallbackTarget::CallTarget)) {}
214
Paul Stewartbdb02e62012-02-22 16:24:33 -0800215 MOCK_METHOD2(CallTarget, void(const Error &error,
216 const IPAddress &address));
217 DNSClient::ClientCallback *callback() { return callback_.get(); }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700218
219 private:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800220 scoped_ptr<DNSClient::ClientCallback> callback_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700221 };
222
223 scoped_ptr<DNSClient> dns_client_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800224 StrictMock<MockEventDispatcher> dispatcher_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700225 string queued_request_;
226 StrictMock<DNSCallbackTarget> callback_target_;
227 StrictMock<MockAres> ares_;
228 StrictMock<MockTime> time_;
229 struct timeval time_val_;
230 struct timeval ares_timeout_;
231 struct hostent hostent_;
232 int ares_result_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800233 Error error_result_;
234 IPAddress address_result_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700235};
236
237class SentinelIOHandler : public IOHandler {
238 public:
239 MOCK_METHOD0(Die, void());
240 virtual ~SentinelIOHandler() { Die(); }
241};
242
243TEST_F(DNSClientTest, Constructor) {
244 vector<string> dns_servers;
245 dns_servers.push_back(kGoodServer);
246 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800247 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700248}
249
250// Receive error because no DNS servers were specified.
251TEST_F(DNSClientTest, NoServers) {
252 CreateClient(vector<string>(), kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800253 Error error;
254 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
255 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700256}
257
258// Receive error because the DNS server IP address is invalid.
259TEST_F(DNSClientTest, TimeoutInvalidServer) {
260 vector<string> dns_servers;
261 dns_servers.push_back(kBadServer);
262 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800263 Error error;
264 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
265 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700266}
267
268// Setup error because InitOptions failed.
269TEST_F(DNSClientTest, InitOptionsFailure) {
270 vector<string> dns_servers;
271 dns_servers.push_back(kGoodServer);
272 CreateClient(dns_servers, kAresTimeoutMS);
273 EXPECT_CALL(ares_, InitOptions(_, _, _))
274 .WillOnce(Return(ARES_EBADFLAGS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800275 Error error;
276 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
277 EXPECT_EQ(Error::kOperationFailed, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700278}
279
280// Fail a second request because one is already in progress.
281TEST_F(DNSClientTest, MultipleRequest) {
282 StartValidRequest();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800283 Error error;
284 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
285 EXPECT_EQ(Error::kInProgress, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700286}
287
288TEST_F(DNSClientTest, GoodRequest) {
289 StartValidRequest();
290 TestValidCompletion();
291}
292
293TEST_F(DNSClientTest, GoodRequestWithTimeout) {
294 StartValidRequest();
295 // Insert an intermediate HandleTimeout callback.
296 AdvanceTime(kAresWaitMS);
297 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD));
298 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
299 CallTimeout();
300 AdvanceTime(kAresWaitMS);
301 TestValidCompletion();
302}
303
304TEST_F(DNSClientTest, GoodRequestWithDNSRead) {
305 StartValidRequest();
306 // Insert an intermediate HandleDNSRead callback.
307 AdvanceTime(kAresWaitMS);
308 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
309 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
310 CallDNSRead();
311 AdvanceTime(kAresWaitMS);
312 TestValidCompletion();
313}
314
315TEST_F(DNSClientTest, GoodRequestWithDNSWrite) {
316 StartValidRequest();
317 // Insert an intermediate HandleDNSWrite callback.
318 AdvanceTime(kAresWaitMS);
319 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, kAresFd));
320 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
321 CallDNSWrite();
322 AdvanceTime(kAresWaitMS);
323 TestValidCompletion();
324}
325
326// Failure due to the timeout occurring during first call to RefreshHandles.
327TEST_F(DNSClientTest, TimeoutFirstRefresh) {
328 SetupRequest(kGoodName, kGoodServer);
329 struct timeval init_time_val = time_val_;
330 AdvanceTime(kAresTimeoutMS);
Paul Stewarte6927402012-01-23 16:11:30 -0800331 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -0700332 .WillOnce(DoAll(SetArgumentPointee<0>(init_time_val), Return(0)))
333 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800334 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(false), _))
335 .Times(0);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700336 EXPECT_CALL(ares_, Destroy(kAresChannel));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800337 Error error;
338 // Expect the DNSClient to post a completion task. However this task will
339 // never run since the Stop() gets called before returning. We confirm
340 // that the task indeed gets canceled below in ExpectReset().
341 ExpectPostCompletionTask();
342 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
343 EXPECT_EQ(Error::kOperationTimeout, error.type());
344 EXPECT_EQ(string(DNSClient::kErrorTimedOut), error.message());
345 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700346}
347
348// Failed request due to timeout within the dns_client.
349TEST_F(DNSClientTest, TimeoutDispatcherEvent) {
350 StartValidRequest();
351 EXPECT_CALL(ares_, ProcessFd(kAresChannel,
352 ARES_SOCKET_BAD, ARES_SOCKET_BAD));
353 AdvanceTime(kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800354 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700355 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800356 EXPECT_CALL(callback_target_, CallTarget(
357 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
358 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700359}
360
361// Failed request due to timeout reported by ARES.
362TEST_F(DNSClientTest, TimeoutFromARES) {
363 StartValidRequest();
364 AdvanceTime(kAresWaitMS);
365 ares_result_ = ARES_ETIMEOUT;
366 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD))
367 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800368 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700369 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800370 EXPECT_CALL(callback_target_, CallTarget(
371 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
372 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700373}
374
375// Failed request due to "host not found" reported by ARES.
376TEST_F(DNSClientTest, HostNotFound) {
377 StartValidRequest();
378 AdvanceTime(kAresWaitMS);
379 ares_result_ = ARES_ENOTFOUND;
380 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
381 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800382 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700383 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800384 EXPECT_CALL(callback_target_, CallTarget(
385 IsFailure(Error::kOperationFailed, DNSClient::kErrorNotFound), _));
386 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700387}
388
389// Make sure IOHandles are deallocated when GetSock() reports them gone.
390TEST_F(DNSClientTest, IOHandleDeallocGetSock) {
391 SetupRequest(kGoodName, kGoodServer);
392 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
393 SentinelIOHandler *io_handler = new SentinelIOHandler();
394 EXPECT_CALL(dispatcher_,
395 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
396 .WillOnce(Return(io_handler));
397 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
398 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800399 Error error;
400 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700401 AdvanceTime(kAresWaitMS);
402 SetInActive();
403 EXPECT_CALL(*io_handler, Die());
404 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
405 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
406 CallDNSRead();
407 EXPECT_CALL(ares_, Destroy(kAresChannel));
408}
409
410// Make sure IOHandles are deallocated when Stop() is called.
411TEST_F(DNSClientTest, IOHandleDeallocStop) {
412 SetupRequest(kGoodName, kGoodServer);
413 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
414 SentinelIOHandler *io_handler = new SentinelIOHandler();
415 EXPECT_CALL(dispatcher_,
416 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
417 .WillOnce(Return(io_handler));
418 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
419 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800420 Error error;
421 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700422 EXPECT_CALL(*io_handler, Die());
423 EXPECT_CALL(ares_, Destroy(kAresChannel));
424 dns_client_->Stop();
425}
426
427} // namespace shill