OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "net/dns/dns_client.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "net/base/big_endian.h" | |
10 #include "net/base/net_log.h" | |
11 #include "net/base/sys_addrinfo.h" | |
12 #include "net/dns/dns_response.h" | |
13 #include "net/dns/dns_session.h" | |
14 #include "net/dns/dns_test_util.h" | |
15 #include "net/socket/socket_test_util.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 // TODO(szym): test DnsClient::Request::Start with synchronous failure | |
19 // TODO(szym): test suffix search and server fallback once implemented | |
20 | |
21 namespace net { | |
22 | |
23 namespace { | |
24 | |
25 class DnsClientTest : public testing::Test { | |
26 public: | |
27 class TestRequestHelper { | |
28 public: | |
29 // If |answer_count| < 0, it is the expected error code. | |
30 TestRequestHelper(const char* name, | |
31 uint16 type, | |
32 const MockWrite& write, | |
33 const MockRead& read, | |
34 int answer_count) { | |
35 // Must include the terminating \x00. | |
36 qname = std::string(name, strlen(name) + 1); | |
37 qtype = type; | |
38 expected_answer_count = answer_count; | |
39 completed = false; | |
40 writes.push_back(write); | |
41 reads.push_back(read); | |
42 ReadBigEndian<uint16>(write.data, &transaction_id); | |
43 data.reset(new StaticSocketDataProvider(&reads[0], reads.size(), | |
44 &writes[0], writes.size())); | |
45 } | |
46 | |
47 void MakeRequest(DnsClient* client) { | |
48 EXPECT_EQ(NULL, request.get()); | |
49 request.reset(client->CreateRequest( | |
50 qname, | |
51 qtype, | |
52 base::Bind(&TestRequestHelper::OnRequestComplete, | |
53 base::Unretained(this)), | |
54 BoundNetLog())); | |
55 EXPECT_EQ(qname, request->qname()); | |
56 EXPECT_EQ(qtype, request->qtype()); | |
57 EXPECT_EQ(ERR_IO_PENDING, request->Start()); | |
58 } | |
59 | |
60 void Cancel() { | |
61 ASSERT_TRUE(request.get() != NULL); | |
62 request.reset(NULL); | |
63 } | |
64 | |
65 void OnRequestComplete(DnsClient::Request* req, | |
66 int rv, | |
67 const DnsResponse* response) { | |
68 EXPECT_FALSE(completed); | |
69 EXPECT_EQ(request.get(), req); | |
70 | |
71 if (expected_answer_count >= 0) { | |
72 EXPECT_EQ(OK, rv); | |
73 EXPECT_EQ(expected_answer_count, response->answer_count()); | |
74 | |
75 DnsRecordParser parser = response->Parser(); | |
76 DnsResourceRecord record; | |
77 for (int i = 0; i < expected_answer_count; ++i) { | |
78 EXPECT_TRUE(parser.ParseRecord(&record)); | |
79 } | |
80 EXPECT_TRUE(parser.AtEnd()); | |
81 | |
82 } else { | |
83 EXPECT_EQ(expected_answer_count, rv); | |
84 EXPECT_EQ(NULL, response); | |
85 } | |
86 | |
87 completed = true; | |
88 } | |
89 | |
90 void CancelOnRequestComplete(DnsClient::Request* req, | |
91 int rv, | |
92 const DnsResponse* response) { | |
93 EXPECT_FALSE(completed); | |
94 Cancel(); | |
95 } | |
96 | |
97 std::string qname; | |
98 uint16 qtype; | |
99 std::vector<MockWrite> writes; | |
100 std::vector<MockRead> reads; | |
101 uint16 transaction_id; // Id from first write. | |
102 scoped_ptr<StaticSocketDataProvider> data; | |
103 scoped_ptr<DnsClient::Request> request; | |
104 int expected_answer_count; | |
105 | |
106 bool completed; | |
107 }; | |
108 | |
109 virtual void SetUp() OVERRIDE { | |
110 helpers_.push_back(new TestRequestHelper( | |
111 kT0DnsName, | |
112 kT0Qtype, | |
113 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | |
114 arraysize(kT0QueryDatagram)), | |
115 MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram), | |
116 arraysize(kT0ResponseDatagram)), | |
117 arraysize(kT0IpAddresses) + 1)); // +1 for CNAME RR | |
118 | |
119 helpers_.push_back(new TestRequestHelper( | |
120 kT1DnsName, | |
121 kT1Qtype, | |
122 MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram), | |
123 arraysize(kT1QueryDatagram)), | |
124 MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram), | |
125 arraysize(kT1ResponseDatagram)), | |
126 arraysize(kT1IpAddresses) + 1)); // +1 for CNAME RR | |
127 | |
128 helpers_.push_back(new TestRequestHelper( | |
129 kT2DnsName, | |
130 kT2Qtype, | |
131 MockWrite(true, reinterpret_cast<const char*>(kT2QueryDatagram), | |
132 arraysize(kT2QueryDatagram)), | |
133 MockRead(true, reinterpret_cast<const char*>(kT2ResponseDatagram), | |
134 arraysize(kT2ResponseDatagram)), | |
135 arraysize(kT2IpAddresses) + 1)); // +1 for CNAME RR | |
136 | |
137 helpers_.push_back(new TestRequestHelper( | |
138 kT3DnsName, | |
139 kT3Qtype, | |
140 MockWrite(true, reinterpret_cast<const char*>(kT3QueryDatagram), | |
141 arraysize(kT3QueryDatagram)), | |
142 MockRead(true, reinterpret_cast<const char*>(kT3ResponseDatagram), | |
143 arraysize(kT3ResponseDatagram)), | |
144 arraysize(kT3IpAddresses) + 2)); // +2 for CNAME RR | |
145 | |
146 CreateClient(); | |
147 } | |
148 | |
149 void CreateClient() { | |
150 MockClientSocketFactory* factory = new MockClientSocketFactory(); | |
151 | |
152 transaction_ids_.clear(); | |
153 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
154 factory->AddSocketDataProvider(helpers_[i]->data.get()); | |
155 transaction_ids_.push_back(static_cast<int>(helpers_[i]->transaction_id)); | |
156 } | |
157 | |
158 DnsConfig config; | |
159 | |
160 IPEndPoint dns_server; | |
161 { | |
162 bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server); | |
163 EXPECT_TRUE(rv); | |
164 } | |
165 config.nameservers.push_back(dns_server); | |
166 | |
167 DnsSession* session = new DnsSession( | |
168 config, | |
169 factory, | |
170 base::Bind(&DnsClientTest::GetNextId, base::Unretained(this)), | |
171 NULL /* NetLog */); | |
172 | |
173 client_.reset(DnsClient::CreateClient(session)); | |
174 } | |
175 | |
176 virtual void TearDown() OVERRIDE { | |
177 STLDeleteElements(&helpers_); | |
178 } | |
179 | |
180 int GetNextId(int min, int max) { | |
181 EXPECT_FALSE(transaction_ids_.empty()); | |
182 int id = transaction_ids_.front(); | |
183 transaction_ids_.pop_front(); | |
184 EXPECT_GE(id, min); | |
185 EXPECT_LE(id, max); | |
186 return id; | |
187 } | |
188 | |
189 protected: | |
190 std::vector<TestRequestHelper*> helpers_; | |
191 std::deque<int> transaction_ids_; | |
192 scoped_ptr<DnsClient> client_; | |
193 }; | |
194 | |
195 TEST_F(DnsClientTest, Lookup) { | |
196 helpers_[0]->MakeRequest(client_.get()); | |
197 | |
198 // Wait until result. | |
199 MessageLoop::current()->RunAllPending(); | |
200 | |
201 EXPECT_TRUE(helpers_[0]->completed); | |
202 } | |
203 | |
204 TEST_F(DnsClientTest, ConcurrentLookup) { | |
205 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
206 helpers_[i]->MakeRequest(client_.get()); | |
207 } | |
208 | |
209 MessageLoop::current()->RunAllPending(); | |
210 | |
211 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
212 EXPECT_TRUE(helpers_[i]->completed); | |
213 } | |
214 } | |
215 | |
216 TEST_F(DnsClientTest, CancelLookup) { | |
217 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
218 helpers_[i]->MakeRequest(client_.get()); | |
219 } | |
220 | |
221 helpers_[0]->Cancel(); | |
222 helpers_[2]->Cancel(); | |
223 | |
224 MessageLoop::current()->RunAllPending(); | |
225 | |
226 EXPECT_FALSE(helpers_[0]->completed); | |
227 EXPECT_TRUE(helpers_[1]->completed); | |
228 EXPECT_FALSE(helpers_[2]->completed); | |
229 EXPECT_TRUE(helpers_[3]->completed); | |
230 } | |
231 | |
232 TEST_F(DnsClientTest, DestroyClient) { | |
233 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
234 helpers_[i]->MakeRequest(client_.get()); | |
235 } | |
236 | |
237 // Destroying the client does not affect running requests. | |
238 client_.reset(NULL); | |
239 | |
240 MessageLoop::current()->RunAllPending(); | |
241 | |
242 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
243 EXPECT_TRUE(helpers_[i]->completed); | |
244 } | |
245 } | |
246 | |
247 TEST_F(DnsClientTest, DestroyRequestFromCallback) { | |
248 // Custom callback to cancel the completing request. | |
249 helpers_[0]->request.reset(client_->CreateRequest( | |
250 helpers_[0]->qname, | |
251 helpers_[0]->qtype, | |
252 base::Bind(&TestRequestHelper::CancelOnRequestComplete, | |
253 base::Unretained(helpers_[0])), | |
254 BoundNetLog())); | |
255 helpers_[0]->request->Start(); | |
256 | |
257 for (unsigned i = 1; i < helpers_.size(); ++i) { | |
258 helpers_[i]->MakeRequest(client_.get()); | |
259 } | |
260 | |
261 MessageLoop::current()->RunAllPending(); | |
262 | |
263 EXPECT_FALSE(helpers_[0]->completed); | |
264 for (unsigned i = 1; i < helpers_.size(); ++i) { | |
265 EXPECT_TRUE(helpers_[i]->completed); | |
266 } | |
267 } | |
268 | |
269 TEST_F(DnsClientTest, HandleFailure) { | |
270 STLDeleteElements(&helpers_); | |
271 // Wrong question. | |
272 helpers_.push_back(new TestRequestHelper( | |
273 kT0DnsName, | |
274 kT0Qtype, | |
275 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | |
276 arraysize(kT0QueryDatagram)), | |
277 MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram), | |
278 arraysize(kT1ResponseDatagram)), | |
279 ERR_DNS_MALFORMED_RESPONSE)); | |
280 | |
281 // Response with NXDOMAIN. | |
282 uint8 nxdomain_response[arraysize(kT0QueryDatagram)]; | |
283 memcpy(nxdomain_response, kT0QueryDatagram, arraysize(nxdomain_response)); | |
284 nxdomain_response[2] &= 0x80; // Response bit. | |
285 nxdomain_response[3] &= 0x03; // NXDOMAIN bit. | |
286 helpers_.push_back(new TestRequestHelper( | |
287 kT0DnsName, | |
288 kT0Qtype, | |
289 MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram), | |
290 arraysize(kT0QueryDatagram)), | |
291 MockRead(true, reinterpret_cast<const char*>(nxdomain_response), | |
292 arraysize(nxdomain_response)), | |
293 ERR_NAME_NOT_RESOLVED)); | |
294 | |
295 CreateClient(); | |
296 | |
297 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
298 helpers_[i]->MakeRequest(client_.get()); | |
299 } | |
300 | |
301 MessageLoop::current()->RunAllPending(); | |
302 | |
303 for (unsigned i = 0; i < helpers_.size(); ++i) { | |
304 EXPECT_TRUE(helpers_[i]->completed); | |
305 } | |
306 } | |
307 | |
308 } // namespace | |
309 | |
310 } // namespace net | |
311 | |
OLD | NEW |