blob: 6a15c2da40fae1a9eba5dcfab311ef07f864e148 [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
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/bind.h>
Paul Stewartc2350ee2011-10-19 12:28:40 -070013#include <base/memory/scoped_ptr.h>
14#include <gtest/gtest.h>
15#include <gmock/gmock.h>
16
Paul Stewartbdb02e62012-02-22 16:24:33 -080017#include "shill/error.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070018#include "shill/event_dispatcher.h"
19#include "shill/io_handler.h"
20#include "shill/mock_ares.h"
21#include "shill/mock_control.h"
22#include "shill/mock_event_dispatcher.h"
23#include "shill/mock_time.h"
24
Eric Shienbrood3e20a232012-02-16 11:35:56 -050025using base::Bind;
26using base::Unretained;
Paul Stewartc2350ee2011-10-19 12:28:40 -070027using std::string;
28using std::vector;
29using testing::_;
30using testing::DoAll;
31using testing::Return;
32using testing::ReturnArg;
33using testing::ReturnNew;
34using testing::Test;
35using testing::SetArgumentPointee;
36using testing::StrEq;
37using testing::StrictMock;
38
39namespace shill {
40
41namespace {
42const char kGoodName[] = "all-systems.mcast.net";
43const char kResult[] = "224.0.0.1";
44const char kGoodServer[] = "8.8.8.8";
45const char kBadServer[] = "10.9xx8.7";
46const char kNetworkInterface[] = "eth0";
47char kReturnAddressList0[] = { 224, 0, 0, 1 };
48char *kReturnAddressList[] = { kReturnAddressList0, NULL };
49char kFakeAresChannelData = 0;
50const ares_channel kAresChannel =
51 reinterpret_cast<ares_channel>(&kFakeAresChannelData);
52const int kAresFd = 10203;
53const int kAresTimeoutMS = 2000; // ARES transaction timeout
54const int kAresWaitMS = 1000; // Time period ARES asks caller to wait
55} // namespace {}
56
Paul Stewartbdb02e62012-02-22 16:24:33 -080057MATCHER_P(IsSuccess, is_success, "") {
58 return is_success == arg.IsSuccess();
59}
60
61MATCHER_P2(IsFailure, failure_type, failure_message, "") {
62 return failure_type == arg.type() && failure_message == arg.message();
63}
64
Paul Stewartc2350ee2011-10-19 12:28:40 -070065class DNSClientTest : public Test {
66 public:
Paul Stewartbdb02e62012-02-22 16:24:33 -080067 DNSClientTest()
68 : ares_result_(ARES_SUCCESS), address_result_(IPAddress::kFamilyUnknown) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070069 time_val_.tv_sec = 0;
70 time_val_.tv_usec = 0;
71 ares_timeout_.tv_sec = kAresWaitMS / 1000;
72 ares_timeout_.tv_usec = (kAresWaitMS % 1000) * 1000;
73 hostent_.h_addrtype = IPAddress::kFamilyIPv4;
74 hostent_.h_length = sizeof(kReturnAddressList0);
75 hostent_.h_addr_list = kReturnAddressList;
76 }
77
78 virtual void SetUp() {
Paul Stewarte6927402012-01-23 16:11:30 -080079 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070080 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
81 SetInActive();
82 }
83
84 virtual void TearDown() {
85 // We need to make sure the dns_client instance releases ares_
86 // before the destructor for DNSClientTest deletes ares_.
87 if (dns_client_.get()) {
88 dns_client_->Stop();
89 }
90 }
91
92 void AdvanceTime(int time_ms) {
93 struct timeval adv_time = { time_ms/1000, (time_ms % 1000) * 1000 };
94 timeradd(&time_val_, &adv_time, &time_val_);
Paul Stewarte6927402012-01-23 16:11:30 -080095 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070096 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
97 }
98
99 void CallReplyCB() {
100 dns_client_->ReceiveDNSReplyCB(dns_client_.get(), ares_result_, 0,
101 &hostent_);
102 }
103
104 void CallDNSRead() {
105 dns_client_->HandleDNSRead(kAresFd);
106 }
107
108 void CallDNSWrite() {
109 dns_client_->HandleDNSWrite(kAresFd);
110 }
111
112 void CallTimeout() {
113 dns_client_->HandleTimeout();
114 }
115
Paul Stewartbdb02e62012-02-22 16:24:33 -0800116 void CallCompletion() {
117 dns_client_->HandleCompletion();
118 }
119
Paul Stewartc2350ee2011-10-19 12:28:40 -0700120 void CreateClient(const vector<string> &dns_servers, int timeout_ms) {
121 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
122 kNetworkInterface,
123 dns_servers,
124 timeout_ms,
125 &dispatcher_,
126 callback_target_.callback()));
127 dns_client_->ares_ = &ares_;
128 dns_client_->time_ = &time_;
129 }
130
131 void SetActive() {
132 // Returns that socket kAresFd is readable.
133 EXPECT_CALL(ares_, GetSock(_, _, _))
134 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kAresFd), Return(1)));
135 EXPECT_CALL(ares_, Timeout(_, _, _))
136 .WillRepeatedly(
137 DoAll(SetArgumentPointee<2>(ares_timeout_), ReturnArg<2>()));
138 }
139
140 void SetInActive() {
141 EXPECT_CALL(ares_, GetSock(_, _, _))
142 .WillRepeatedly(Return(0));
143 EXPECT_CALL(ares_, Timeout(_, _, _))
144 .WillRepeatedly(ReturnArg<1>());
145 }
146
147 void SetupRequest(const string &name, const string &server) {
148 vector<string> dns_servers;
149 dns_servers.push_back(server);
150 CreateClient(dns_servers, kAresTimeoutMS);
151 // These expectations are fulfilled when dns_client_->Start() is called.
152 EXPECT_CALL(ares_, InitOptions(_, _, _))
153 .WillOnce(DoAll(SetArgumentPointee<0>(kAresChannel),
154 Return(ARES_SUCCESS)));
155 EXPECT_CALL(ares_, SetLocalDev(kAresChannel, StrEq(kNetworkInterface)))
156 .Times(1);
157 EXPECT_CALL(ares_, GetHostByName(kAresChannel, StrEq(name), _, _, _));
158 }
159
160 void StartValidRequest() {
161 SetupRequest(kGoodName, kGoodServer);
162 EXPECT_CALL(dispatcher_,
163 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
164 .WillOnce(ReturnNew<IOHandler>());
165 SetActive();
166 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800167 Error error;
168 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
169 EXPECT_TRUE(error.IsSuccess());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700170 EXPECT_CALL(ares_, Destroy(kAresChannel));
171 }
172
173 void TestValidCompletion() {
Paul Stewartc2350ee2011-10-19 12:28:40 -0700174 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
175 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800176 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700177 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800178
179 // Make sure that the address value is correct as held in the DNSClient.
180 ASSERT_TRUE(dns_client_->address_.IsValid());
181 IPAddress ipaddr(dns_client_->address_.family());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700182 ASSERT_TRUE(ipaddr.SetAddressFromString(kResult));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800183 EXPECT_TRUE(ipaddr.Equals(dns_client_->address_));
184
185 // Make sure the callback gets called with a success result, and save
186 // the callback address argument in |address_result_|.
187 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(true), _))
188 .WillOnce(Invoke(this, &DNSClientTest::SaveCallbackArgs));
189 CallCompletion();
190
191 // Make sure the address was successfully passed to the callback.
192 EXPECT_TRUE(ipaddr.Equals(address_result_));
193 EXPECT_TRUE(dns_client_->address_.IsDefault());
194 }
195
196 void SaveCallbackArgs(const Error &error, const IPAddress &address) {
197 error_result_.CopyFrom(error);
198 address_result_ = address;
199 }
200
201 void ExpectPostCompletionTask() {
202 EXPECT_CALL(dispatcher_, PostTask(_));
203 }
204
205 void ExpectReset() {
206 EXPECT_TRUE(dns_client_->address_.family() == IPAddress::kFamilyIPv4);
207 EXPECT_TRUE(dns_client_->address_.IsDefault());
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500208 EXPECT_FALSE(dns_client_->weak_ptr_factory_.HasWeakPtrs());
Paul Stewartbdb02e62012-02-22 16:24:33 -0800209 EXPECT_FALSE(dns_client_->resolver_state_.get());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700210 }
211
212 protected:
213 class DNSCallbackTarget {
214 public:
215 DNSCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500216 : callback_(Bind(&DNSCallbackTarget::CallTarget, Unretained(this))) {}
Paul Stewartc2350ee2011-10-19 12:28:40 -0700217
Paul Stewartbdb02e62012-02-22 16:24:33 -0800218 MOCK_METHOD2(CallTarget, void(const Error &error,
219 const IPAddress &address));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500220 const DNSClient::ClientCallback &callback() { return callback_; }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700221
222 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500223 DNSClient::ClientCallback callback_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700224 };
225
226 scoped_ptr<DNSClient> dns_client_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800227 StrictMock<MockEventDispatcher> dispatcher_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700228 string queued_request_;
229 StrictMock<DNSCallbackTarget> callback_target_;
230 StrictMock<MockAres> ares_;
231 StrictMock<MockTime> time_;
232 struct timeval time_val_;
233 struct timeval ares_timeout_;
234 struct hostent hostent_;
235 int ares_result_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800236 Error error_result_;
237 IPAddress address_result_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700238};
239
240class SentinelIOHandler : public IOHandler {
241 public:
242 MOCK_METHOD0(Die, void());
243 virtual ~SentinelIOHandler() { Die(); }
244};
245
246TEST_F(DNSClientTest, Constructor) {
247 vector<string> dns_servers;
248 dns_servers.push_back(kGoodServer);
249 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800250 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700251}
252
253// Receive error because no DNS servers were specified.
254TEST_F(DNSClientTest, NoServers) {
255 CreateClient(vector<string>(), kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800256 Error error;
257 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
258 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700259}
260
261// Receive error because the DNS server IP address is invalid.
262TEST_F(DNSClientTest, TimeoutInvalidServer) {
263 vector<string> dns_servers;
264 dns_servers.push_back(kBadServer);
265 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800266 Error error;
267 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
268 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700269}
270
271// Setup error because InitOptions failed.
272TEST_F(DNSClientTest, InitOptionsFailure) {
273 vector<string> dns_servers;
274 dns_servers.push_back(kGoodServer);
275 CreateClient(dns_servers, kAresTimeoutMS);
276 EXPECT_CALL(ares_, InitOptions(_, _, _))
277 .WillOnce(Return(ARES_EBADFLAGS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800278 Error error;
279 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
280 EXPECT_EQ(Error::kOperationFailed, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700281}
282
283// Fail a second request because one is already in progress.
284TEST_F(DNSClientTest, MultipleRequest) {
285 StartValidRequest();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800286 Error error;
287 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
288 EXPECT_EQ(Error::kInProgress, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700289}
290
291TEST_F(DNSClientTest, GoodRequest) {
292 StartValidRequest();
293 TestValidCompletion();
294}
295
296TEST_F(DNSClientTest, GoodRequestWithTimeout) {
297 StartValidRequest();
298 // Insert an intermediate HandleTimeout callback.
299 AdvanceTime(kAresWaitMS);
300 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD));
301 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
302 CallTimeout();
303 AdvanceTime(kAresWaitMS);
304 TestValidCompletion();
305}
306
307TEST_F(DNSClientTest, GoodRequestWithDNSRead) {
308 StartValidRequest();
309 // Insert an intermediate HandleDNSRead callback.
310 AdvanceTime(kAresWaitMS);
311 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
312 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
313 CallDNSRead();
314 AdvanceTime(kAresWaitMS);
315 TestValidCompletion();
316}
317
318TEST_F(DNSClientTest, GoodRequestWithDNSWrite) {
319 StartValidRequest();
320 // Insert an intermediate HandleDNSWrite callback.
321 AdvanceTime(kAresWaitMS);
322 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, kAresFd));
323 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
324 CallDNSWrite();
325 AdvanceTime(kAresWaitMS);
326 TestValidCompletion();
327}
328
329// Failure due to the timeout occurring during first call to RefreshHandles.
330TEST_F(DNSClientTest, TimeoutFirstRefresh) {
331 SetupRequest(kGoodName, kGoodServer);
332 struct timeval init_time_val = time_val_;
333 AdvanceTime(kAresTimeoutMS);
Paul Stewarte6927402012-01-23 16:11:30 -0800334 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -0700335 .WillOnce(DoAll(SetArgumentPointee<0>(init_time_val), Return(0)))
336 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800337 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(false), _))
338 .Times(0);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700339 EXPECT_CALL(ares_, Destroy(kAresChannel));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800340 Error error;
341 // Expect the DNSClient to post a completion task. However this task will
342 // never run since the Stop() gets called before returning. We confirm
343 // that the task indeed gets canceled below in ExpectReset().
344 ExpectPostCompletionTask();
345 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
346 EXPECT_EQ(Error::kOperationTimeout, error.type());
347 EXPECT_EQ(string(DNSClient::kErrorTimedOut), error.message());
348 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700349}
350
351// Failed request due to timeout within the dns_client.
352TEST_F(DNSClientTest, TimeoutDispatcherEvent) {
353 StartValidRequest();
354 EXPECT_CALL(ares_, ProcessFd(kAresChannel,
355 ARES_SOCKET_BAD, ARES_SOCKET_BAD));
356 AdvanceTime(kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800357 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700358 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800359 EXPECT_CALL(callback_target_, CallTarget(
360 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
361 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700362}
363
364// Failed request due to timeout reported by ARES.
365TEST_F(DNSClientTest, TimeoutFromARES) {
366 StartValidRequest();
367 AdvanceTime(kAresWaitMS);
368 ares_result_ = ARES_ETIMEOUT;
369 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD))
370 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800371 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700372 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800373 EXPECT_CALL(callback_target_, CallTarget(
374 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
375 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700376}
377
378// Failed request due to "host not found" reported by ARES.
379TEST_F(DNSClientTest, HostNotFound) {
380 StartValidRequest();
381 AdvanceTime(kAresWaitMS);
382 ares_result_ = ARES_ENOTFOUND;
383 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
384 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800385 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700386 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800387 EXPECT_CALL(callback_target_, CallTarget(
388 IsFailure(Error::kOperationFailed, DNSClient::kErrorNotFound), _));
389 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700390}
391
392// Make sure IOHandles are deallocated when GetSock() reports them gone.
393TEST_F(DNSClientTest, IOHandleDeallocGetSock) {
394 SetupRequest(kGoodName, kGoodServer);
395 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
396 SentinelIOHandler *io_handler = new SentinelIOHandler();
397 EXPECT_CALL(dispatcher_,
398 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
399 .WillOnce(Return(io_handler));
400 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
401 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800402 Error error;
403 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700404 AdvanceTime(kAresWaitMS);
405 SetInActive();
406 EXPECT_CALL(*io_handler, Die());
407 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
408 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
409 CallDNSRead();
410 EXPECT_CALL(ares_, Destroy(kAresChannel));
411}
412
413// Make sure IOHandles are deallocated when Stop() is called.
414TEST_F(DNSClientTest, IOHandleDeallocStop) {
415 SetupRequest(kGoodName, kGoodServer);
416 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
417 SentinelIOHandler *io_handler = new SentinelIOHandler();
418 EXPECT_CALL(dispatcher_,
419 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
420 .WillOnce(Return(io_handler));
421 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
422 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800423 Error error;
424 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700425 EXPECT_CALL(*io_handler, Die());
426 EXPECT_CALL(ares_, Destroy(kAresChannel));
427 dns_client_->Stop();
428}
429
430} // namespace shill