blob: 148f55e135e9b4d895c487101daaf1be8a8441ab [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";
Han Shenfc349252012-08-30 11:36:04 -070047char kReturnAddressList0[] = { static_cast<char>(224), 0, 0, 1 };
Paul Stewartc2350ee2011-10-19 12:28:40 -070048char *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());
Paul Stewartbdb02e62012-02-22 16:24:33 -0800208 EXPECT_FALSE(dns_client_->resolver_state_.get());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700209 }
210
211 protected:
212 class DNSCallbackTarget {
213 public:
214 DNSCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500215 : callback_(Bind(&DNSCallbackTarget::CallTarget, Unretained(this))) {}
Paul Stewartc2350ee2011-10-19 12:28:40 -0700216
Paul Stewartbdb02e62012-02-22 16:24:33 -0800217 MOCK_METHOD2(CallTarget, void(const Error &error,
218 const IPAddress &address));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500219 const DNSClient::ClientCallback &callback() { return callback_; }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700220
221 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500222 DNSClient::ClientCallback callback_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700223 };
224
225 scoped_ptr<DNSClient> dns_client_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800226 StrictMock<MockEventDispatcher> dispatcher_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700227 string queued_request_;
228 StrictMock<DNSCallbackTarget> callback_target_;
229 StrictMock<MockAres> ares_;
230 StrictMock<MockTime> time_;
231 struct timeval time_val_;
232 struct timeval ares_timeout_;
233 struct hostent hostent_;
234 int ares_result_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800235 Error error_result_;
236 IPAddress address_result_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700237};
238
239class SentinelIOHandler : public IOHandler {
240 public:
241 MOCK_METHOD0(Die, void());
242 virtual ~SentinelIOHandler() { Die(); }
243};
244
245TEST_F(DNSClientTest, Constructor) {
246 vector<string> dns_servers;
247 dns_servers.push_back(kGoodServer);
248 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800249 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700250}
251
252// Receive error because no DNS servers were specified.
253TEST_F(DNSClientTest, NoServers) {
254 CreateClient(vector<string>(), kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800255 Error error;
256 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
257 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700258}
259
260// Receive error because the DNS server IP address is invalid.
261TEST_F(DNSClientTest, TimeoutInvalidServer) {
262 vector<string> dns_servers;
263 dns_servers.push_back(kBadServer);
264 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800265 Error error;
266 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
267 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700268}
269
270// Setup error because InitOptions failed.
271TEST_F(DNSClientTest, InitOptionsFailure) {
272 vector<string> dns_servers;
273 dns_servers.push_back(kGoodServer);
274 CreateClient(dns_servers, kAresTimeoutMS);
275 EXPECT_CALL(ares_, InitOptions(_, _, _))
276 .WillOnce(Return(ARES_EBADFLAGS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800277 Error error;
278 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
279 EXPECT_EQ(Error::kOperationFailed, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700280}
281
282// Fail a second request because one is already in progress.
283TEST_F(DNSClientTest, MultipleRequest) {
284 StartValidRequest();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800285 Error error;
286 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
287 EXPECT_EQ(Error::kInProgress, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700288}
289
290TEST_F(DNSClientTest, GoodRequest) {
291 StartValidRequest();
292 TestValidCompletion();
293}
294
295TEST_F(DNSClientTest, GoodRequestWithTimeout) {
296 StartValidRequest();
297 // Insert an intermediate HandleTimeout callback.
298 AdvanceTime(kAresWaitMS);
299 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD));
300 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
301 CallTimeout();
302 AdvanceTime(kAresWaitMS);
303 TestValidCompletion();
304}
305
306TEST_F(DNSClientTest, GoodRequestWithDNSRead) {
307 StartValidRequest();
308 // Insert an intermediate HandleDNSRead callback.
309 AdvanceTime(kAresWaitMS);
310 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
311 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
312 CallDNSRead();
313 AdvanceTime(kAresWaitMS);
314 TestValidCompletion();
315}
316
317TEST_F(DNSClientTest, GoodRequestWithDNSWrite) {
318 StartValidRequest();
319 // Insert an intermediate HandleDNSWrite callback.
320 AdvanceTime(kAresWaitMS);
321 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, kAresFd));
322 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
323 CallDNSWrite();
324 AdvanceTime(kAresWaitMS);
325 TestValidCompletion();
326}
327
328// Failure due to the timeout occurring during first call to RefreshHandles.
329TEST_F(DNSClientTest, TimeoutFirstRefresh) {
330 SetupRequest(kGoodName, kGoodServer);
331 struct timeval init_time_val = time_val_;
332 AdvanceTime(kAresTimeoutMS);
Paul Stewarte6927402012-01-23 16:11:30 -0800333 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -0700334 .WillOnce(DoAll(SetArgumentPointee<0>(init_time_val), Return(0)))
335 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800336 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(false), _))
337 .Times(0);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700338 EXPECT_CALL(ares_, Destroy(kAresChannel));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800339 Error error;
340 // Expect the DNSClient to post a completion task. However this task will
341 // never run since the Stop() gets called before returning. We confirm
342 // that the task indeed gets canceled below in ExpectReset().
343 ExpectPostCompletionTask();
344 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
345 EXPECT_EQ(Error::kOperationTimeout, error.type());
346 EXPECT_EQ(string(DNSClient::kErrorTimedOut), error.message());
347 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700348}
349
350// Failed request due to timeout within the dns_client.
351TEST_F(DNSClientTest, TimeoutDispatcherEvent) {
352 StartValidRequest();
353 EXPECT_CALL(ares_, ProcessFd(kAresChannel,
354 ARES_SOCKET_BAD, ARES_SOCKET_BAD));
355 AdvanceTime(kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800356 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700357 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800358 EXPECT_CALL(callback_target_, CallTarget(
359 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
360 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700361}
362
363// Failed request due to timeout reported by ARES.
364TEST_F(DNSClientTest, TimeoutFromARES) {
365 StartValidRequest();
366 AdvanceTime(kAresWaitMS);
367 ares_result_ = ARES_ETIMEOUT;
368 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD))
369 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800370 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700371 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800372 EXPECT_CALL(callback_target_, CallTarget(
373 IsFailure(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
374 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700375}
376
377// Failed request due to "host not found" reported by ARES.
378TEST_F(DNSClientTest, HostNotFound) {
379 StartValidRequest();
380 AdvanceTime(kAresWaitMS);
381 ares_result_ = ARES_ENOTFOUND;
382 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
383 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800384 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700385 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800386 EXPECT_CALL(callback_target_, CallTarget(
387 IsFailure(Error::kOperationFailed, DNSClient::kErrorNotFound), _));
388 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700389}
390
391// Make sure IOHandles are deallocated when GetSock() reports them gone.
392TEST_F(DNSClientTest, IOHandleDeallocGetSock) {
393 SetupRequest(kGoodName, kGoodServer);
394 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
395 SentinelIOHandler *io_handler = new SentinelIOHandler();
396 EXPECT_CALL(dispatcher_,
397 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
398 .WillOnce(Return(io_handler));
399 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
400 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800401 Error error;
402 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700403 AdvanceTime(kAresWaitMS);
404 SetInActive();
405 EXPECT_CALL(*io_handler, Die());
406 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
407 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
408 CallDNSRead();
409 EXPECT_CALL(ares_, Destroy(kAresChannel));
410}
411
412// Make sure IOHandles are deallocated when Stop() is called.
413TEST_F(DNSClientTest, IOHandleDeallocStop) {
414 SetupRequest(kGoodName, kGoodServer);
415 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
416 SentinelIOHandler *io_handler = new SentinelIOHandler();
417 EXPECT_CALL(dispatcher_,
418 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
419 .WillOnce(Return(io_handler));
420 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
421 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800422 Error error;
423 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700424 EXPECT_CALL(*io_handler, Die());
425 EXPECT_CALL(ares_, Destroy(kAresChannel));
426 dns_client_->Stop();
427}
428
429} // namespace shill