blob: f9085cce928d300e9aafa1c668ce412514b222c7 [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>
Paul Stewartc2350ee2011-10-19 12:28:40 -070014
Paul Stewartbdb02e62012-02-22 16:24:33 -080015#include "shill/error.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070016#include "shill/event_dispatcher.h"
17#include "shill/io_handler.h"
18#include "shill/mock_ares.h"
19#include "shill/mock_control.h"
20#include "shill/mock_event_dispatcher.h"
21#include "shill/mock_time.h"
Ben Chanbe277dd2014-02-05 17:26:47 -080022#include "shill/testing.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070023
Eric Shienbrood3e20a232012-02-16 11:35:56 -050024using base::Bind;
25using base::Unretained;
Paul Stewartc2350ee2011-10-19 12:28:40 -070026using std::string;
27using std::vector;
28using testing::_;
29using testing::DoAll;
Ben Chanbe277dd2014-02-05 17:26:47 -080030using testing::Not;
Paul Stewartc2350ee2011-10-19 12:28:40 -070031using 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
Alex Vakulenko8a532292014-06-16 17:18:44 -070055} // namespace
Paul Stewartc2350ee2011-10-19 12:28:40 -070056
57class DNSClientTest : public Test {
58 public:
Paul Stewartbdb02e62012-02-22 16:24:33 -080059 DNSClientTest()
60 : ares_result_(ARES_SUCCESS), address_result_(IPAddress::kFamilyUnknown) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070061 time_val_.tv_sec = 0;
62 time_val_.tv_usec = 0;
63 ares_timeout_.tv_sec = kAresWaitMS / 1000;
64 ares_timeout_.tv_usec = (kAresWaitMS % 1000) * 1000;
65 hostent_.h_addrtype = IPAddress::kFamilyIPv4;
66 hostent_.h_length = sizeof(kReturnAddressList0);
67 hostent_.h_addr_list = kReturnAddressList;
68 }
69
70 virtual void SetUp() {
Paul Stewarte6927402012-01-23 16:11:30 -080071 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070072 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
73 SetInActive();
74 }
75
76 virtual void TearDown() {
77 // We need to make sure the dns_client instance releases ares_
78 // before the destructor for DNSClientTest deletes ares_.
79 if (dns_client_.get()) {
80 dns_client_->Stop();
81 }
82 }
83
84 void AdvanceTime(int time_ms) {
85 struct timeval adv_time = { time_ms/1000, (time_ms % 1000) * 1000 };
86 timeradd(&time_val_, &adv_time, &time_val_);
Paul Stewarte6927402012-01-23 16:11:30 -080087 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -070088 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
89 }
90
91 void CallReplyCB() {
92 dns_client_->ReceiveDNSReplyCB(dns_client_.get(), ares_result_, 0,
93 &hostent_);
94 }
95
96 void CallDNSRead() {
97 dns_client_->HandleDNSRead(kAresFd);
98 }
99
100 void CallDNSWrite() {
101 dns_client_->HandleDNSWrite(kAresFd);
102 }
103
104 void CallTimeout() {
105 dns_client_->HandleTimeout();
106 }
107
Paul Stewartbdb02e62012-02-22 16:24:33 -0800108 void CallCompletion() {
109 dns_client_->HandleCompletion();
110 }
111
Paul Stewartc2350ee2011-10-19 12:28:40 -0700112 void CreateClient(const vector<string> &dns_servers, int timeout_ms) {
113 dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
114 kNetworkInterface,
115 dns_servers,
116 timeout_ms,
117 &dispatcher_,
118 callback_target_.callback()));
119 dns_client_->ares_ = &ares_;
120 dns_client_->time_ = &time_;
121 }
122
123 void SetActive() {
124 // Returns that socket kAresFd is readable.
125 EXPECT_CALL(ares_, GetSock(_, _, _))
126 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kAresFd), Return(1)));
127 EXPECT_CALL(ares_, Timeout(_, _, _))
128 .WillRepeatedly(
129 DoAll(SetArgumentPointee<2>(ares_timeout_), ReturnArg<2>()));
130 }
131
132 void SetInActive() {
133 EXPECT_CALL(ares_, GetSock(_, _, _))
134 .WillRepeatedly(Return(0));
135 EXPECT_CALL(ares_, Timeout(_, _, _))
136 .WillRepeatedly(ReturnArg<1>());
137 }
138
139 void SetupRequest(const string &name, const string &server) {
140 vector<string> dns_servers;
141 dns_servers.push_back(server);
142 CreateClient(dns_servers, kAresTimeoutMS);
143 // These expectations are fulfilled when dns_client_->Start() is called.
144 EXPECT_CALL(ares_, InitOptions(_, _, _))
145 .WillOnce(DoAll(SetArgumentPointee<0>(kAresChannel),
146 Return(ARES_SUCCESS)));
147 EXPECT_CALL(ares_, SetLocalDev(kAresChannel, StrEq(kNetworkInterface)))
148 .Times(1);
149 EXPECT_CALL(ares_, GetHostByName(kAresChannel, StrEq(name), _, _, _));
150 }
151
152 void StartValidRequest() {
153 SetupRequest(kGoodName, kGoodServer);
154 EXPECT_CALL(dispatcher_,
155 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
156 .WillOnce(ReturnNew<IOHandler>());
157 SetActive();
158 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800159 Error error;
160 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
161 EXPECT_TRUE(error.IsSuccess());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700162 EXPECT_CALL(ares_, Destroy(kAresChannel));
163 }
164
165 void TestValidCompletion() {
Paul Stewartc2350ee2011-10-19 12:28:40 -0700166 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
167 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800168 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700169 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800170
171 // Make sure that the address value is correct as held in the DNSClient.
172 ASSERT_TRUE(dns_client_->address_.IsValid());
173 IPAddress ipaddr(dns_client_->address_.family());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700174 ASSERT_TRUE(ipaddr.SetAddressFromString(kResult));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800175 EXPECT_TRUE(ipaddr.Equals(dns_client_->address_));
176
177 // Make sure the callback gets called with a success result, and save
178 // the callback address argument in |address_result_|.
Ben Chanbe277dd2014-02-05 17:26:47 -0800179 EXPECT_CALL(callback_target_, CallTarget(IsSuccess(), _))
Paul Stewartbdb02e62012-02-22 16:24:33 -0800180 .WillOnce(Invoke(this, &DNSClientTest::SaveCallbackArgs));
181 CallCompletion();
182
183 // Make sure the address was successfully passed to the callback.
184 EXPECT_TRUE(ipaddr.Equals(address_result_));
185 EXPECT_TRUE(dns_client_->address_.IsDefault());
186 }
187
188 void SaveCallbackArgs(const Error &error, const IPAddress &address) {
189 error_result_.CopyFrom(error);
190 address_result_ = address;
191 }
192
193 void ExpectPostCompletionTask() {
194 EXPECT_CALL(dispatcher_, PostTask(_));
195 }
196
197 void ExpectReset() {
198 EXPECT_TRUE(dns_client_->address_.family() == IPAddress::kFamilyIPv4);
199 EXPECT_TRUE(dns_client_->address_.IsDefault());
Paul Stewartbdb02e62012-02-22 16:24:33 -0800200 EXPECT_FALSE(dns_client_->resolver_state_.get());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700201 }
202
203 protected:
204 class DNSCallbackTarget {
205 public:
206 DNSCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500207 : callback_(Bind(&DNSCallbackTarget::CallTarget, Unretained(this))) {}
Paul Stewartc2350ee2011-10-19 12:28:40 -0700208
Paul Stewartbdb02e62012-02-22 16:24:33 -0800209 MOCK_METHOD2(CallTarget, void(const Error &error,
210 const IPAddress &address));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500211 const DNSClient::ClientCallback &callback() { return callback_; }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700212
213 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500214 DNSClient::ClientCallback callback_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700215 };
216
217 scoped_ptr<DNSClient> dns_client_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800218 StrictMock<MockEventDispatcher> dispatcher_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700219 string queued_request_;
220 StrictMock<DNSCallbackTarget> callback_target_;
221 StrictMock<MockAres> ares_;
222 StrictMock<MockTime> time_;
223 struct timeval time_val_;
224 struct timeval ares_timeout_;
225 struct hostent hostent_;
226 int ares_result_;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800227 Error error_result_;
228 IPAddress address_result_;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700229};
230
231class SentinelIOHandler : public IOHandler {
232 public:
233 MOCK_METHOD0(Die, void());
234 virtual ~SentinelIOHandler() { Die(); }
235};
236
237TEST_F(DNSClientTest, Constructor) {
238 vector<string> dns_servers;
239 dns_servers.push_back(kGoodServer);
240 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800241 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700242}
243
244// Receive error because no DNS servers were specified.
245TEST_F(DNSClientTest, NoServers) {
246 CreateClient(vector<string>(), kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800247 Error error;
248 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
249 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700250}
251
252// Receive error because the DNS server IP address is invalid.
253TEST_F(DNSClientTest, TimeoutInvalidServer) {
254 vector<string> dns_servers;
255 dns_servers.push_back(kBadServer);
256 CreateClient(dns_servers, kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800257 Error error;
258 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
259 EXPECT_EQ(Error::kInvalidArguments, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700260}
261
262// Setup error because InitOptions failed.
263TEST_F(DNSClientTest, InitOptionsFailure) {
264 vector<string> dns_servers;
265 dns_servers.push_back(kGoodServer);
266 CreateClient(dns_servers, kAresTimeoutMS);
267 EXPECT_CALL(ares_, InitOptions(_, _, _))
268 .WillOnce(Return(ARES_EBADFLAGS));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800269 Error error;
270 EXPECT_FALSE(dns_client_->Start(kGoodName, &error));
271 EXPECT_EQ(Error::kOperationFailed, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700272}
273
274// Fail a second request because one is already in progress.
275TEST_F(DNSClientTest, MultipleRequest) {
276 StartValidRequest();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800277 Error error;
278 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
279 EXPECT_EQ(Error::kInProgress, error.type());
Paul Stewartc2350ee2011-10-19 12:28:40 -0700280}
281
282TEST_F(DNSClientTest, GoodRequest) {
283 StartValidRequest();
284 TestValidCompletion();
285}
286
287TEST_F(DNSClientTest, GoodRequestWithTimeout) {
288 StartValidRequest();
289 // Insert an intermediate HandleTimeout callback.
290 AdvanceTime(kAresWaitMS);
291 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD));
292 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
293 CallTimeout();
294 AdvanceTime(kAresWaitMS);
295 TestValidCompletion();
296}
297
298TEST_F(DNSClientTest, GoodRequestWithDNSRead) {
299 StartValidRequest();
300 // Insert an intermediate HandleDNSRead callback.
301 AdvanceTime(kAresWaitMS);
302 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
303 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
304 CallDNSRead();
305 AdvanceTime(kAresWaitMS);
306 TestValidCompletion();
307}
308
309TEST_F(DNSClientTest, GoodRequestWithDNSWrite) {
310 StartValidRequest();
311 // Insert an intermediate HandleDNSWrite callback.
312 AdvanceTime(kAresWaitMS);
313 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, kAresFd));
314 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
315 CallDNSWrite();
316 AdvanceTime(kAresWaitMS);
317 TestValidCompletion();
318}
319
320// Failure due to the timeout occurring during first call to RefreshHandles.
321TEST_F(DNSClientTest, TimeoutFirstRefresh) {
322 SetupRequest(kGoodName, kGoodServer);
323 struct timeval init_time_val = time_val_;
324 AdvanceTime(kAresTimeoutMS);
Paul Stewarte6927402012-01-23 16:11:30 -0800325 EXPECT_CALL(time_, GetTimeMonotonic(_))
Paul Stewartc2350ee2011-10-19 12:28:40 -0700326 .WillOnce(DoAll(SetArgumentPointee<0>(init_time_val), Return(0)))
327 .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
Ben Chanbe277dd2014-02-05 17:26:47 -0800328 EXPECT_CALL(callback_target_, CallTarget(Not(IsSuccess()), _))
Paul Stewartbdb02e62012-02-22 16:24:33 -0800329 .Times(0);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700330 EXPECT_CALL(ares_, Destroy(kAresChannel));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800331 Error error;
332 // Expect the DNSClient to post a completion task. However this task will
333 // never run since the Stop() gets called before returning. We confirm
334 // that the task indeed gets canceled below in ExpectReset().
335 ExpectPostCompletionTask();
336 ASSERT_FALSE(dns_client_->Start(kGoodName, &error));
337 EXPECT_EQ(Error::kOperationTimeout, error.type());
338 EXPECT_EQ(string(DNSClient::kErrorTimedOut), error.message());
339 ExpectReset();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700340}
341
342// Failed request due to timeout within the dns_client.
343TEST_F(DNSClientTest, TimeoutDispatcherEvent) {
344 StartValidRequest();
345 EXPECT_CALL(ares_, ProcessFd(kAresChannel,
346 ARES_SOCKET_BAD, ARES_SOCKET_BAD));
347 AdvanceTime(kAresTimeoutMS);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800348 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700349 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800350 EXPECT_CALL(callback_target_, CallTarget(
Ben Chanbe277dd2014-02-05 17:26:47 -0800351 ErrorIs(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800352 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700353}
354
355// Failed request due to timeout reported by ARES.
356TEST_F(DNSClientTest, TimeoutFromARES) {
357 StartValidRequest();
358 AdvanceTime(kAresWaitMS);
359 ares_result_ = ARES_ETIMEOUT;
360 EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD))
361 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800362 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700363 CallTimeout();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800364 EXPECT_CALL(callback_target_, CallTarget(
Ben Chanbe277dd2014-02-05 17:26:47 -0800365 ErrorIs(Error::kOperationTimeout, DNSClient::kErrorTimedOut), _));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800366 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700367}
368
369// Failed request due to "host not found" reported by ARES.
370TEST_F(DNSClientTest, HostNotFound) {
371 StartValidRequest();
372 AdvanceTime(kAresWaitMS);
373 ares_result_ = ARES_ENOTFOUND;
374 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
375 .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800376 ExpectPostCompletionTask();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700377 CallDNSRead();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800378 EXPECT_CALL(callback_target_, CallTarget(
Ben Chanbe277dd2014-02-05 17:26:47 -0800379 ErrorIs(Error::kOperationFailed, DNSClient::kErrorNotFound), _));
Paul Stewartbdb02e62012-02-22 16:24:33 -0800380 CallCompletion();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700381}
382
383// Make sure IOHandles are deallocated when GetSock() reports them gone.
384TEST_F(DNSClientTest, IOHandleDeallocGetSock) {
385 SetupRequest(kGoodName, kGoodServer);
386 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
387 SentinelIOHandler *io_handler = new SentinelIOHandler();
388 EXPECT_CALL(dispatcher_,
389 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
390 .WillOnce(Return(io_handler));
391 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
392 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800393 Error error;
394 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700395 AdvanceTime(kAresWaitMS);
396 SetInActive();
397 EXPECT_CALL(*io_handler, Die());
398 EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
399 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
400 CallDNSRead();
401 EXPECT_CALL(ares_, Destroy(kAresChannel));
402}
403
404// Make sure IOHandles are deallocated when Stop() is called.
405TEST_F(DNSClientTest, IOHandleDeallocStop) {
406 SetupRequest(kGoodName, kGoodServer);
407 // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
408 SentinelIOHandler *io_handler = new SentinelIOHandler();
409 EXPECT_CALL(dispatcher_,
410 CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
411 .WillOnce(Return(io_handler));
412 EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
413 SetActive();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800414 Error error;
415 ASSERT_TRUE(dns_client_->Start(kGoodName, &error));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700416 EXPECT_CALL(*io_handler, Die());
417 EXPECT_CALL(ares_, Destroy(kAresChannel));
418 dns_client_->Stop();
419}
420
421} // namespace shill