1// Copyright 2013 The Chromium 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 "chrome/utility/local_discovery/service_discovery_client_impl.h"
6#include "net/dns/mdns_client_impl.h"
7#include "net/dns/mock_mdns_socket_factory.h"
8#include "testing/gmock/include/gmock/gmock.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using ::testing::_;
12
13namespace local_discovery {
14
15namespace {
16
17const uint8 kSamplePacketA[] = {
18  // Header
19  0x00, 0x00,               // ID is zeroed out
20  0x81, 0x80,               // Standard query response, RA, no error
21  0x00, 0x00,               // No questions (for simplicity)
22  0x00, 0x01,               // 1 RR (answers)
23  0x00, 0x00,               // 0 authority RRs
24  0x00, 0x00,               // 0 additional RRs
25
26  0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
27  0x05, 'l', 'o', 'c', 'a', 'l',
28  0x00,
29  0x00, 0x01,        // TYPE is A.
30  0x00, 0x01,        // CLASS is IN.
31  0x00, 0x00,        // TTL (4 bytes) is 16 seconds.
32  0x00, 0x10,
33  0x00, 0x04,        // RDLENGTH is 4 bytes.
34  0x01, 0x02,
35  0x03, 0x04,
36};
37
38const uint8 kSamplePacketAAAA[] = {
39  // Header
40  0x00, 0x00,               // ID is zeroed out
41  0x81, 0x80,               // Standard query response, RA, no error
42  0x00, 0x00,               // No questions (for simplicity)
43  0x00, 0x01,               // 1 RR (answers)
44  0x00, 0x00,               // 0 authority RRs
45  0x00, 0x00,               // 0 additional RRs
46
47  0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
48  0x05, 'l', 'o', 'c', 'a', 'l',
49  0x00,
50  0x00, 0x1C,        // TYPE is AAAA.
51  0x00, 0x01,        // CLASS is IN.
52  0x00, 0x00,        // TTL (4 bytes) is 16 seconds.
53  0x00, 0x10,
54  0x00, 0x10,        // RDLENGTH is 4 bytes.
55  0x00, 0x0A, 0x00, 0x00,
56  0x00, 0x00, 0x00, 0x00,
57  0x00, 0x01, 0x00, 0x02,
58  0x00, 0x03, 0x00, 0x04,
59};
60
61class LocalDomainResolverTest : public testing::Test {
62 public:
63  virtual void SetUp() OVERRIDE {
64    mdns_client_.StartListening(&socket_factory_);
65  }
66
67  std::string IPAddressToStringWithEmpty(const net::IPAddressNumber& address) {
68    if (address.empty()) return "";
69    return net::IPAddressToString(address);
70  }
71
72  void AddressCallback(bool resolved,
73                       const net::IPAddressNumber& address_ipv4,
74                       const net::IPAddressNumber& address_ipv6) {
75      AddressCallbackInternal(resolved,
76                              IPAddressToStringWithEmpty(address_ipv4),
77                              IPAddressToStringWithEmpty(address_ipv6));
78  }
79
80  void RunFor(base::TimeDelta time_period) {
81    base::CancelableCallback<void()> callback(base::Bind(
82        &base::MessageLoop::Quit,
83        base::Unretained(base::MessageLoop::current())));
84    base::MessageLoop::current()->PostDelayedTask(
85        FROM_HERE, callback.callback(), time_period);
86
87    base::MessageLoop::current()->Run();
88    callback.Cancel();
89  }
90
91  MOCK_METHOD3(AddressCallbackInternal,
92               void(bool resolved,
93                    std::string address_ipv4,
94                    std::string address_ipv6));
95
96  net::MockMDnsSocketFactory socket_factory_;
97  net::MDnsClientImpl mdns_client_;
98  base::MessageLoop message_loop_;
99};
100
101TEST_F(LocalDomainResolverTest, ResolveDomainA) {
102  LocalDomainResolverImpl resolver(
103      "myhello.local", net::ADDRESS_FAMILY_IPV4,
104      base::Bind(&LocalDomainResolverTest::AddressCallback,
105                 base::Unretained(this)), &mdns_client_);
106
107  EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);  // Twice per query
108
109  resolver.Start();
110
111  EXPECT_CALL(*this, AddressCallbackInternal(true, "1.2.3.4", ""));
112
113  socket_factory_.SimulateReceive(kSamplePacketA, sizeof(kSamplePacketA));
114}
115
116TEST_F(LocalDomainResolverTest, ResolveDomainAAAA) {
117  LocalDomainResolverImpl resolver(
118      "myhello.local", net::ADDRESS_FAMILY_IPV6,
119      base::Bind(&LocalDomainResolverTest::AddressCallback,
120                 base::Unretained(this)), &mdns_client_);
121
122  EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);  // Twice per query
123
124  resolver.Start();
125
126  EXPECT_CALL(*this, AddressCallbackInternal(true, "", "a::1:2:3:4"));
127
128  socket_factory_.SimulateReceive(kSamplePacketAAAA, sizeof(kSamplePacketAAAA));
129}
130
131TEST_F(LocalDomainResolverTest, ResolveDomainAnyOneAvailable) {
132  LocalDomainResolverImpl resolver(
133      "myhello.local", net::ADDRESS_FAMILY_UNSPECIFIED,
134      base::Bind(&LocalDomainResolverTest::AddressCallback,
135                 base::Unretained(this)), &mdns_client_);
136
137  EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(4);  // Twice per query
138
139  resolver.Start();
140
141  socket_factory_.SimulateReceive(kSamplePacketAAAA, sizeof(kSamplePacketAAAA));
142
143  EXPECT_CALL(*this, AddressCallbackInternal(true, "", "a::1:2:3:4"));
144
145  RunFor(base::TimeDelta::FromMilliseconds(150));
146}
147
148
149TEST_F(LocalDomainResolverTest, ResolveDomainAnyBothAvailable) {
150  LocalDomainResolverImpl resolver(
151      "myhello.local", net::ADDRESS_FAMILY_UNSPECIFIED,
152      base::Bind(&LocalDomainResolverTest::AddressCallback,
153                 base::Unretained(this)), &mdns_client_);
154
155  EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(4);  // Twice per query
156
157  resolver.Start();
158
159  EXPECT_CALL(*this, AddressCallbackInternal(true, "1.2.3.4", "a::1:2:3:4"));
160
161  socket_factory_.SimulateReceive(kSamplePacketAAAA, sizeof(kSamplePacketAAAA));
162
163  socket_factory_.SimulateReceive(kSamplePacketA, sizeof(kSamplePacketA));
164}
165
166TEST_F(LocalDomainResolverTest, ResolveDomainNone) {
167  LocalDomainResolverImpl resolver(
168      "myhello.local", net::ADDRESS_FAMILY_UNSPECIFIED,
169      base::Bind(&LocalDomainResolverTest::AddressCallback,
170                 base::Unretained(this)), &mdns_client_);
171
172  EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(4);  // Twice per query
173
174  resolver.Start();
175
176  EXPECT_CALL(*this, AddressCallbackInternal(false, "", ""));
177
178  RunFor(base::TimeDelta::FromSeconds(4));
179}
180
181}  // namespace
182
183}  // namespace local_discovery
184