dns_client_unittest.cc revision c2350ee42c6734750ef8a57bae20f23a224cbc53
1// Copyright (c) 2011 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/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
16#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"
22
23using std::string;
24using std::vector;
25using testing::_;
26using testing::DoAll;
27using testing::Return;
28using testing::ReturnArg;
29using testing::ReturnNew;
30using testing::Test;
31using testing::SetArgumentPointee;
32using testing::StrEq;
33using testing::StrictMock;
34
35namespace shill {
36
37namespace {
38const char kGoodName[] = "all-systems.mcast.net";
39const char kResult[] = "224.0.0.1";
40const char kGoodServer[] = "8.8.8.8";
41const char kBadServer[] = "10.9xx8.7";
42const char kNetworkInterface[] = "eth0";
43char kReturnAddressList0[] = { 224, 0, 0, 1 };
44char *kReturnAddressList[] = { kReturnAddressList0, NULL };
45char kFakeAresChannelData = 0;
46const ares_channel kAresChannel =
47    reinterpret_cast<ares_channel>(&kFakeAresChannelData);
48const int kAresFd = 10203;
49const int kAresTimeoutMS = 2000;  // ARES transaction timeout
50const int kAresWaitMS = 1000;     // Time period ARES asks caller to wait
51}  // namespace {}
52
53class DNSClientTest : public Test {
54 public:
55  DNSClientTest() : ares_result_(ARES_SUCCESS) {
56    time_val_.tv_sec = 0;
57    time_val_.tv_usec = 0;
58    ares_timeout_.tv_sec = kAresWaitMS / 1000;
59    ares_timeout_.tv_usec = (kAresWaitMS % 1000) * 1000;
60    hostent_.h_addrtype = IPAddress::kFamilyIPv4;
61    hostent_.h_length = sizeof(kReturnAddressList0);
62    hostent_.h_addr_list = kReturnAddressList;
63  }
64
65  virtual void SetUp() {
66    EXPECT_CALL(time_, GetTimeOfDay(_, _))
67        .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
68    SetInActive();
69  }
70
71  virtual void TearDown() {
72    // We need to make sure the dns_client instance releases ares_
73    // before the destructor for DNSClientTest deletes ares_.
74    if (dns_client_.get()) {
75      dns_client_->Stop();
76    }
77  }
78
79  void AdvanceTime(int time_ms) {
80    struct timeval adv_time = { time_ms/1000, (time_ms % 1000) * 1000 };
81    timeradd(&time_val_, &adv_time, &time_val_);
82    EXPECT_CALL(time_, GetTimeOfDay(_, _))
83        .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
84  }
85
86  void CallReplyCB() {
87    dns_client_->ReceiveDNSReplyCB(dns_client_.get(), ares_result_, 0,
88                                   &hostent_);
89  }
90
91  void CallDNSRead() {
92    dns_client_->HandleDNSRead(kAresFd);
93  }
94
95  void CallDNSWrite() {
96    dns_client_->HandleDNSWrite(kAresFd);
97  }
98
99  void CallTimeout() {
100    dns_client_->HandleTimeout();
101  }
102
103  void CreateClient(const vector<string> &dns_servers, int timeout_ms) {
104    dns_client_.reset(new DNSClient(IPAddress::kFamilyIPv4,
105                                    kNetworkInterface,
106                                    dns_servers,
107                                    timeout_ms,
108                                    &dispatcher_,
109                                    callback_target_.callback()));
110    dns_client_->ares_ = &ares_;
111    dns_client_->time_ = &time_;
112  }
113
114  void SetActive() {
115    // Returns that socket kAresFd is readable.
116    EXPECT_CALL(ares_, GetSock(_, _, _))
117        .WillRepeatedly(DoAll(SetArgumentPointee<1>(kAresFd), Return(1)));
118    EXPECT_CALL(ares_, Timeout(_, _, _))
119        .WillRepeatedly(
120            DoAll(SetArgumentPointee<2>(ares_timeout_), ReturnArg<2>()));
121  }
122
123  void SetInActive() {
124    EXPECT_CALL(ares_, GetSock(_, _, _))
125        .WillRepeatedly(Return(0));
126    EXPECT_CALL(ares_, Timeout(_, _, _))
127        .WillRepeatedly(ReturnArg<1>());
128  }
129
130  void SetupRequest(const string &name, const string &server) {
131    vector<string> dns_servers;
132    dns_servers.push_back(server);
133    CreateClient(dns_servers, kAresTimeoutMS);
134    // These expectations are fulfilled when dns_client_->Start() is called.
135    EXPECT_CALL(ares_, InitOptions(_, _, _))
136        .WillOnce(DoAll(SetArgumentPointee<0>(kAresChannel),
137                        Return(ARES_SUCCESS)));
138    EXPECT_CALL(ares_, SetLocalDev(kAresChannel, StrEq(kNetworkInterface)))
139        .Times(1);
140    EXPECT_CALL(ares_, GetHostByName(kAresChannel, StrEq(name), _, _, _));
141  }
142
143  void StartValidRequest() {
144    SetupRequest(kGoodName, kGoodServer);
145    EXPECT_CALL(dispatcher_,
146                CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
147        .WillOnce(ReturnNew<IOHandler>());
148    SetActive();
149    EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
150    ASSERT_TRUE(dns_client_->Start(kGoodName));
151    EXPECT_CALL(ares_, Destroy(kAresChannel));
152  }
153
154  void TestValidCompletion() {
155    EXPECT_CALL(callback_target_, CallTarget(true));
156    EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
157        .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
158    CallDNSRead();
159    ASSERT_TRUE(dns_client_->address().IsValid());
160    IPAddress ipaddr(dns_client_->address().family());
161    ASSERT_TRUE(ipaddr.SetAddressFromString(kResult));
162    EXPECT_TRUE(ipaddr.Equals(dns_client_->address()));
163  }
164
165 protected:
166  class DNSCallbackTarget {
167   public:
168    DNSCallbackTarget()
169        : callback_(NewCallback(this, &DNSCallbackTarget::CallTarget)) {}
170
171    MOCK_METHOD1(CallTarget, void(bool success));
172    Callback1<bool>::Type *callback() { return callback_.get(); }
173
174   private:
175    scoped_ptr<Callback1<bool>::Type> callback_;
176  };
177
178  scoped_ptr<DNSClient> dns_client_;
179  MockEventDispatcher dispatcher_;
180  string queued_request_;
181  StrictMock<DNSCallbackTarget> callback_target_;
182  StrictMock<MockAres> ares_;
183  StrictMock<MockTime> time_;
184  struct timeval time_val_;
185  struct timeval ares_timeout_;
186  struct hostent hostent_;
187  int ares_result_;
188};
189
190class SentinelIOHandler : public IOHandler {
191 public:
192  MOCK_METHOD0(Die, void());
193  virtual ~SentinelIOHandler() { Die(); }
194};
195
196TEST_F(DNSClientTest, Constructor) {
197  vector<string> dns_servers;
198  dns_servers.push_back(kGoodServer);
199  CreateClient(dns_servers, kAresTimeoutMS);
200  EXPECT_TRUE(dns_client_->address().family() == IPAddress::kFamilyIPv4);
201  EXPECT_TRUE(dns_client_->address().IsDefault());
202}
203
204// Receive error because no DNS servers were specified.
205TEST_F(DNSClientTest, NoServers) {
206  CreateClient(vector<string>(), kAresTimeoutMS);
207  EXPECT_FALSE(dns_client_->Start(kGoodName));
208}
209
210// Receive error because the DNS server IP address is invalid.
211TEST_F(DNSClientTest, TimeoutInvalidServer) {
212  vector<string> dns_servers;
213  dns_servers.push_back(kBadServer);
214  CreateClient(dns_servers, kAresTimeoutMS);
215  ASSERT_FALSE(dns_client_->Start(kGoodName));
216}
217
218// Setup error because InitOptions failed.
219TEST_F(DNSClientTest, InitOptionsFailure) {
220  vector<string> dns_servers;
221  dns_servers.push_back(kGoodServer);
222  CreateClient(dns_servers, kAresTimeoutMS);
223  EXPECT_CALL(ares_, InitOptions(_, _, _))
224      .WillOnce(Return(ARES_EBADFLAGS));
225  EXPECT_FALSE(dns_client_->Start(kGoodName));
226}
227
228// Fail a second request because one is already in progress.
229TEST_F(DNSClientTest, MultipleRequest) {
230  StartValidRequest();
231  ASSERT_FALSE(dns_client_->Start(kGoodName));
232}
233
234TEST_F(DNSClientTest, GoodRequest) {
235  StartValidRequest();
236  TestValidCompletion();
237}
238
239TEST_F(DNSClientTest, GoodRequestWithTimeout) {
240  StartValidRequest();
241  // Insert an intermediate HandleTimeout callback.
242  AdvanceTime(kAresWaitMS);
243  EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD));
244  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
245  CallTimeout();
246  AdvanceTime(kAresWaitMS);
247  TestValidCompletion();
248}
249
250TEST_F(DNSClientTest, GoodRequestWithDNSRead) {
251  StartValidRequest();
252  // Insert an intermediate HandleDNSRead callback.
253  AdvanceTime(kAresWaitMS);
254  EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
255  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
256  CallDNSRead();
257  AdvanceTime(kAresWaitMS);
258  TestValidCompletion();
259}
260
261TEST_F(DNSClientTest, GoodRequestWithDNSWrite) {
262  StartValidRequest();
263  // Insert an intermediate HandleDNSWrite callback.
264  AdvanceTime(kAresWaitMS);
265  EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, kAresFd));
266  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
267  CallDNSWrite();
268  AdvanceTime(kAresWaitMS);
269  TestValidCompletion();
270}
271
272// Failure due to the timeout occurring during first call to RefreshHandles.
273TEST_F(DNSClientTest, TimeoutFirstRefresh) {
274  SetupRequest(kGoodName, kGoodServer);
275  struct timeval init_time_val = time_val_;
276  AdvanceTime(kAresTimeoutMS);
277  EXPECT_CALL(time_, GetTimeOfDay(_, _))
278      .WillOnce(DoAll(SetArgumentPointee<0>(init_time_val), Return(0)))
279      .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
280  EXPECT_CALL(callback_target_, CallTarget(false));
281  EXPECT_CALL(ares_, Destroy(kAresChannel));
282  ASSERT_FALSE(dns_client_->Start(kGoodName));
283  EXPECT_EQ(string(DNSClient::kErrorTimedOut), dns_client_->error());
284}
285
286// Failed request due to timeout within the dns_client.
287TEST_F(DNSClientTest, TimeoutDispatcherEvent) {
288  StartValidRequest();
289  EXPECT_CALL(ares_, ProcessFd(kAresChannel,
290                               ARES_SOCKET_BAD, ARES_SOCKET_BAD));
291  AdvanceTime(kAresTimeoutMS);
292  EXPECT_CALL(callback_target_, CallTarget(false));
293  CallTimeout();
294}
295
296// Failed request due to timeout reported by ARES.
297TEST_F(DNSClientTest, TimeoutFromARES) {
298  StartValidRequest();
299  AdvanceTime(kAresWaitMS);
300  ares_result_ = ARES_ETIMEOUT;
301  EXPECT_CALL(ares_, ProcessFd(kAresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD))
302        .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
303  EXPECT_CALL(callback_target_, CallTarget(false));
304  CallTimeout();
305  EXPECT_EQ(string(DNSClient::kErrorTimedOut), dns_client_->error());
306}
307
308// Failed request due to "host not found" reported by ARES.
309TEST_F(DNSClientTest, HostNotFound) {
310  StartValidRequest();
311  AdvanceTime(kAresWaitMS);
312  ares_result_ = ARES_ENOTFOUND;
313  EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD))
314      .WillOnce(InvokeWithoutArgs(this, &DNSClientTest::CallReplyCB));
315  EXPECT_CALL(callback_target_, CallTarget(false));
316  CallDNSRead();
317  EXPECT_EQ(string(DNSClient::kErrorNotFound), dns_client_->error());
318}
319
320// Make sure IOHandles are deallocated when GetSock() reports them gone.
321TEST_F(DNSClientTest, IOHandleDeallocGetSock) {
322  SetupRequest(kGoodName, kGoodServer);
323  // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
324  SentinelIOHandler *io_handler = new SentinelIOHandler();
325  EXPECT_CALL(dispatcher_,
326              CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
327      .WillOnce(Return(io_handler));
328  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
329  SetActive();
330  ASSERT_TRUE(dns_client_->Start(kGoodName));
331  AdvanceTime(kAresWaitMS);
332  SetInActive();
333  EXPECT_CALL(*io_handler, Die());
334  EXPECT_CALL(ares_, ProcessFd(kAresChannel, kAresFd, ARES_SOCKET_BAD));
335  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
336  CallDNSRead();
337  EXPECT_CALL(ares_, Destroy(kAresChannel));
338}
339
340// Make sure IOHandles are deallocated when Stop() is called.
341TEST_F(DNSClientTest, IOHandleDeallocStop) {
342  SetupRequest(kGoodName, kGoodServer);
343  // This isn't any kind of scoped/ref pointer because we are tracking dealloc.
344  SentinelIOHandler *io_handler = new SentinelIOHandler();
345  EXPECT_CALL(dispatcher_,
346              CreateReadyHandler(kAresFd, IOHandler::kModeInput, _))
347      .WillOnce(Return(io_handler));
348  EXPECT_CALL(dispatcher_, PostDelayedTask(_, kAresWaitMS));
349  SetActive();
350  ASSERT_TRUE(dns_client_->Start(kGoodName));
351  EXPECT_CALL(*io_handler, Die());
352  EXPECT_CALL(ares_, Destroy(kAresChannel));
353  dns_client_->Stop();
354}
355
356}  // namespace shill
357