OLD | NEW |
| (Empty) |
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 <queue> | |
6 | |
7 #include "base/memory/ref_counted.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "net/base/rand_callback.h" | |
10 #include "net/base/test_completion_callback.h" | |
11 #include "net/dns/mdns_client_impl.h" | |
12 #include "net/dns/mock_mdns_socket_factory.h" | |
13 #include "net/dns/record_rdata.h" | |
14 #include "net/udp/udp_client_socket.h" | |
15 #include "testing/gmock/include/gmock/gmock.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 using ::testing::Invoke; | |
19 using ::testing::InvokeWithoutArgs; | |
20 using ::testing::StrictMock; | |
21 using ::testing::NiceMock; | |
22 using ::testing::Exactly; | |
23 using ::testing::Return; | |
24 using ::testing::SaveArg; | |
25 using ::testing::_; | |
26 | |
27 namespace net { | |
28 | |
29 namespace { | |
30 | |
31 const uint8 kSamplePacket1[] = { | |
32 // Header | |
33 0x00, 0x00, // ID is zeroed out | |
34 0x81, 0x80, // Standard query response, RA, no error | |
35 0x00, 0x00, // No questions (for simplicity) | |
36 0x00, 0x02, // 2 RRs (answers) | |
37 0x00, 0x00, // 0 authority RRs | |
38 0x00, 0x00, // 0 additional RRs | |
39 | |
40 // Answer 1 | |
41 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
42 0x04, '_', 't', 'c', 'p', | |
43 0x05, 'l', 'o', 'c', 'a', 'l', | |
44 0x00, | |
45 0x00, 0x0c, // TYPE is PTR. | |
46 0x00, 0x01, // CLASS is IN. | |
47 0x00, 0x00, // TTL (4 bytes) is 1 second; | |
48 0x00, 0x01, | |
49 0x00, 0x08, // RDLENGTH is 8 bytes. | |
50 0x05, 'h', 'e', 'l', 'l', 'o', | |
51 0xc0, 0x0c, | |
52 | |
53 // Answer 2 | |
54 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', | |
55 0xc0, 0x14, // Pointer to "._tcp.local" | |
56 0x00, 0x0c, // TYPE is PTR. | |
57 0x00, 0x01, // CLASS is IN. | |
58 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds. | |
59 0x24, 0x75, | |
60 0x00, 0x08, // RDLENGTH is 8 bytes. | |
61 0x05, 'h', 'e', 'l', 'l', 'o', | |
62 0xc0, 0x32 | |
63 }; | |
64 | |
65 const uint8 kCorruptedPacketBadQuestion[] = { | |
66 // Header | |
67 0x00, 0x00, // ID is zeroed out | |
68 0x81, 0x80, // Standard query response, RA, no error | |
69 0x00, 0x01, // One question | |
70 0x00, 0x02, // 2 RRs (answers) | |
71 0x00, 0x00, // 0 authority RRs | |
72 0x00, 0x00, // 0 additional RRs | |
73 | |
74 // Question is corrupted and cannot be read. | |
75 0x99, 'h', 'e', 'l', 'l', 'o', | |
76 0x00, | |
77 0x00, 0x00, | |
78 0x00, 0x00, | |
79 | |
80 // Answer 1 | |
81 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
82 0x04, '_', 't', 'c', 'p', | |
83 0x05, 'l', 'o', 'c', 'a', 'l', | |
84 0x00, | |
85 0x00, 0x0c, // TYPE is PTR. | |
86 0x00, 0x01, // CLASS is IN. | |
87 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
88 0x24, 0x74, | |
89 0x00, 0x99, // RDLENGTH is impossible | |
90 0x05, 'h', 'e', 'l', 'l', 'o', | |
91 0xc0, 0x0c, | |
92 | |
93 // Answer 2 | |
94 0x08, '_', 'p', 'r', // Useless trailing data. | |
95 }; | |
96 | |
97 const uint8 kCorruptedPacketUnsalvagable[] = { | |
98 // Header | |
99 0x00, 0x00, // ID is zeroed out | |
100 0x81, 0x80, // Standard query response, RA, no error | |
101 0x00, 0x00, // No questions (for simplicity) | |
102 0x00, 0x02, // 2 RRs (answers) | |
103 0x00, 0x00, // 0 authority RRs | |
104 0x00, 0x00, // 0 additional RRs | |
105 | |
106 // Answer 1 | |
107 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
108 0x04, '_', 't', 'c', 'p', | |
109 0x05, 'l', 'o', 'c', 'a', 'l', | |
110 0x00, | |
111 0x00, 0x0c, // TYPE is PTR. | |
112 0x00, 0x01, // CLASS is IN. | |
113 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
114 0x24, 0x74, | |
115 0x00, 0x99, // RDLENGTH is impossible | |
116 0x05, 'h', 'e', 'l', 'l', 'o', | |
117 0xc0, 0x0c, | |
118 | |
119 // Answer 2 | |
120 0x08, '_', 'p', 'r', // Useless trailing data. | |
121 }; | |
122 | |
123 const uint8 kCorruptedPacketDoubleRecord[] = { | |
124 // Header | |
125 0x00, 0x00, // ID is zeroed out | |
126 0x81, 0x80, // Standard query response, RA, no error | |
127 0x00, 0x00, // No questions (for simplicity) | |
128 0x00, 0x02, // 2 RRs (answers) | |
129 0x00, 0x00, // 0 authority RRs | |
130 0x00, 0x00, // 0 additional RRs | |
131 | |
132 // Answer 1 | |
133 0x06, 'p', 'r', 'i', 'v', 'e', 't', | |
134 0x05, 'l', 'o', 'c', 'a', 'l', | |
135 0x00, | |
136 0x00, 0x01, // TYPE is A. | |
137 0x00, 0x01, // CLASS is IN. | |
138 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
139 0x24, 0x74, | |
140 0x00, 0x04, // RDLENGTH is 4 | |
141 0x05, 0x03, | |
142 0xc0, 0x0c, | |
143 | |
144 // Answer 2 -- Same key | |
145 0x06, 'p', 'r', 'i', 'v', 'e', 't', | |
146 0x05, 'l', 'o', 'c', 'a', 'l', | |
147 0x00, | |
148 0x00, 0x01, // TYPE is A. | |
149 0x00, 0x01, // CLASS is IN. | |
150 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
151 0x24, 0x74, | |
152 0x00, 0x04, // RDLENGTH is 4 | |
153 0x02, 0x03, | |
154 0x04, 0x05, | |
155 }; | |
156 | |
157 const uint8 kCorruptedPacketSalvagable[] = { | |
158 // Header | |
159 0x00, 0x00, // ID is zeroed out | |
160 0x81, 0x80, // Standard query response, RA, no error | |
161 0x00, 0x00, // No questions (for simplicity) | |
162 0x00, 0x02, // 2 RRs (answers) | |
163 0x00, 0x00, // 0 authority RRs | |
164 0x00, 0x00, // 0 additional RRs | |
165 | |
166 // Answer 1 | |
167 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
168 0x04, '_', 't', 'c', 'p', | |
169 0x05, 'l', 'o', 'c', 'a', 'l', | |
170 0x00, | |
171 0x00, 0x0c, // TYPE is PTR. | |
172 0x00, 0x01, // CLASS is IN. | |
173 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
174 0x24, 0x74, | |
175 0x00, 0x08, // RDLENGTH is 8 bytes. | |
176 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format. | |
177 0xc0, 0x0c, | |
178 | |
179 // Answer 2 | |
180 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', | |
181 0xc0, 0x14, // Pointer to "._tcp.local" | |
182 0x00, 0x0c, // TYPE is PTR. | |
183 0x00, 0x01, // CLASS is IN. | |
184 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds. | |
185 0x24, 0x75, | |
186 0x00, 0x08, // RDLENGTH is 8 bytes. | |
187 0x05, 'h', 'e', 'l', 'l', 'o', | |
188 0xc0, 0x32 | |
189 }; | |
190 | |
191 const uint8 kSamplePacket2[] = { | |
192 // Header | |
193 0x00, 0x00, // ID is zeroed out | |
194 0x81, 0x80, // Standard query response, RA, no error | |
195 0x00, 0x00, // No questions (for simplicity) | |
196 0x00, 0x02, // 2 RRs (answers) | |
197 0x00, 0x00, // 0 authority RRs | |
198 0x00, 0x00, // 0 additional RRs | |
199 | |
200 // Answer 1 | |
201 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
202 0x04, '_', 't', 'c', 'p', | |
203 0x05, 'l', 'o', 'c', 'a', 'l', | |
204 0x00, | |
205 0x00, 0x0c, // TYPE is PTR. | |
206 0x00, 0x01, // CLASS is IN. | |
207 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
208 0x24, 0x74, | |
209 0x00, 0x08, // RDLENGTH is 8 bytes. | |
210 0x05, 'z', 'z', 'z', 'z', 'z', | |
211 0xc0, 0x0c, | |
212 | |
213 // Answer 2 | |
214 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', | |
215 0xc0, 0x14, // Pointer to "._tcp.local" | |
216 0x00, 0x0c, // TYPE is PTR. | |
217 0x00, 0x01, // CLASS is IN. | |
218 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
219 0x24, 0x74, | |
220 0x00, 0x08, // RDLENGTH is 8 bytes. | |
221 0x05, 'z', 'z', 'z', 'z', 'z', | |
222 0xc0, 0x32 | |
223 }; | |
224 | |
225 const uint8 kQueryPacketPrivet[] = { | |
226 // Header | |
227 0x00, 0x00, // ID is zeroed out | |
228 0x00, 0x00, // No flags. | |
229 0x00, 0x01, // One question. | |
230 0x00, 0x00, // 0 RRs (answers) | |
231 0x00, 0x00, // 0 authority RRs | |
232 0x00, 0x00, // 0 additional RRs | |
233 | |
234 // Question | |
235 // This part is echoed back from the respective query. | |
236 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
237 0x04, '_', 't', 'c', 'p', | |
238 0x05, 'l', 'o', 'c', 'a', 'l', | |
239 0x00, | |
240 0x00, 0x0c, // TYPE is PTR. | |
241 0x00, 0x01, // CLASS is IN. | |
242 }; | |
243 | |
244 const uint8 kQueryPacketPrivetA[] = { | |
245 // Header | |
246 0x00, 0x00, // ID is zeroed out | |
247 0x00, 0x00, // No flags. | |
248 0x00, 0x01, // One question. | |
249 0x00, 0x00, // 0 RRs (answers) | |
250 0x00, 0x00, // 0 authority RRs | |
251 0x00, 0x00, // 0 additional RRs | |
252 | |
253 // Question | |
254 // This part is echoed back from the respective query. | |
255 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
256 0x04, '_', 't', 'c', 'p', | |
257 0x05, 'l', 'o', 'c', 'a', 'l', | |
258 0x00, | |
259 0x00, 0x01, // TYPE is A. | |
260 0x00, 0x01, // CLASS is IN. | |
261 }; | |
262 | |
263 const uint8 kSamplePacketAdditionalOnly[] = { | |
264 // Header | |
265 0x00, 0x00, // ID is zeroed out | |
266 0x81, 0x80, // Standard query response, RA, no error | |
267 0x00, 0x00, // No questions (for simplicity) | |
268 0x00, 0x00, // 2 RRs (answers) | |
269 0x00, 0x00, // 0 authority RRs | |
270 0x00, 0x01, // 0 additional RRs | |
271 | |
272 // Answer 1 | |
273 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
274 0x04, '_', 't', 'c', 'p', | |
275 0x05, 'l', 'o', 'c', 'a', 'l', | |
276 0x00, | |
277 0x00, 0x0c, // TYPE is PTR. | |
278 0x00, 0x01, // CLASS is IN. | |
279 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
280 0x24, 0x74, | |
281 0x00, 0x08, // RDLENGTH is 8 bytes. | |
282 0x05, 'h', 'e', 'l', 'l', 'o', | |
283 0xc0, 0x0c, | |
284 }; | |
285 | |
286 const uint8 kSamplePacketNsec[] = { | |
287 // Header | |
288 0x00, 0x00, // ID is zeroed out | |
289 0x81, 0x80, // Standard query response, RA, no error | |
290 0x00, 0x00, // No questions (for simplicity) | |
291 0x00, 0x01, // 1 RR (answers) | |
292 0x00, 0x00, // 0 authority RRs | |
293 0x00, 0x00, // 0 additional RRs | |
294 | |
295 // Answer 1 | |
296 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
297 0x04, '_', 't', 'c', 'p', | |
298 0x05, 'l', 'o', 'c', 'a', 'l', | |
299 0x00, | |
300 0x00, 0x2f, // TYPE is NSEC. | |
301 0x00, 0x01, // CLASS is IN. | |
302 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
303 0x24, 0x74, | |
304 0x00, 0x06, // RDLENGTH is 6 bytes. | |
305 0xc0, 0x0c, | |
306 0x00, 0x02, 0x00, 0x08 // Only A record present | |
307 }; | |
308 | |
309 const uint8 kSamplePacketAPrivet[] = { | |
310 // Header | |
311 0x00, 0x00, // ID is zeroed out | |
312 0x81, 0x80, // Standard query response, RA, no error | |
313 0x00, 0x00, // No questions (for simplicity) | |
314 0x00, 0x01, // 1 RR (answers) | |
315 0x00, 0x00, // 0 authority RRs | |
316 0x00, 0x00, // 0 additional RRs | |
317 | |
318 // Answer 1 | |
319 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
320 0x04, '_', 't', 'c', 'p', | |
321 0x05, 'l', 'o', 'c', 'a', 'l', | |
322 0x00, | |
323 0x00, 0x01, // TYPE is A. | |
324 0x00, 0x01, // CLASS is IN. | |
325 0x00, 0x00, // TTL (4 bytes) is 5 seconds | |
326 0x00, 0x05, | |
327 0x00, 0x04, // RDLENGTH is 4 bytes. | |
328 0xc0, 0x0c, | |
329 0x00, 0x02, | |
330 }; | |
331 | |
332 const uint8 kSamplePacketGoodbye[] = { | |
333 // Header | |
334 0x00, 0x00, // ID is zeroed out | |
335 0x81, 0x80, // Standard query response, RA, no error | |
336 0x00, 0x00, // No questions (for simplicity) | |
337 0x00, 0x01, // 2 RRs (answers) | |
338 0x00, 0x00, // 0 authority RRs | |
339 0x00, 0x00, // 0 additional RRs | |
340 | |
341 // Answer 1 | |
342 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', | |
343 0x04, '_', 't', 'c', 'p', | |
344 0x05, 'l', 'o', 'c', 'a', 'l', | |
345 0x00, | |
346 0x00, 0x0c, // TYPE is PTR. | |
347 0x00, 0x01, // CLASS is IN. | |
348 0x00, 0x00, // TTL (4 bytes) is zero; | |
349 0x00, 0x00, | |
350 0x00, 0x08, // RDLENGTH is 8 bytes. | |
351 0x05, 'z', 'z', 'z', 'z', 'z', | |
352 0xc0, 0x0c, | |
353 }; | |
354 | |
355 std::string MakeString(const uint8* data, unsigned size) { | |
356 return std::string(reinterpret_cast<const char*>(data), size); | |
357 } | |
358 | |
359 class PtrRecordCopyContainer { | |
360 public: | |
361 PtrRecordCopyContainer() {} | |
362 ~PtrRecordCopyContainer() {} | |
363 | |
364 bool is_set() const { return set_; } | |
365 | |
366 void SaveWithDummyArg(int unused, const RecordParsed* value) { | |
367 Save(value); | |
368 } | |
369 | |
370 void Save(const RecordParsed* value) { | |
371 set_ = true; | |
372 name_ = value->name(); | |
373 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain(); | |
374 ttl_ = value->ttl(); | |
375 } | |
376 | |
377 bool IsRecordWith(std::string name, std::string ptrdomain) { | |
378 return set_ && name_ == name && ptrdomain_ == ptrdomain; | |
379 } | |
380 | |
381 const std::string& name() { return name_; } | |
382 const std::string& ptrdomain() { return ptrdomain_; } | |
383 int ttl() { return ttl_; } | |
384 | |
385 private: | |
386 bool set_; | |
387 std::string name_; | |
388 std::string ptrdomain_; | |
389 int ttl_; | |
390 }; | |
391 | |
392 class MDnsTest : public ::testing::Test { | |
393 public: | |
394 virtual void SetUp() override; | |
395 void DeleteTransaction(); | |
396 void DeleteBothListeners(); | |
397 void RunFor(base::TimeDelta time_period); | |
398 void Stop(); | |
399 | |
400 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result, | |
401 const RecordParsed* record)); | |
402 | |
403 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result, | |
404 const RecordParsed* record)); | |
405 | |
406 | |
407 protected: | |
408 void ExpectPacket(const uint8* packet, unsigned size); | |
409 void SimulatePacketReceive(const uint8* packet, unsigned size); | |
410 | |
411 MDnsClientImpl test_client_; | |
412 IPEndPoint mdns_ipv4_endpoint_; | |
413 StrictMock<MockMDnsSocketFactory> socket_factory_; | |
414 | |
415 // Transactions and listeners that can be deleted by class methods for | |
416 // reentrancy tests. | |
417 scoped_ptr<MDnsTransaction> transaction_; | |
418 scoped_ptr<MDnsListener> listener1_; | |
419 scoped_ptr<MDnsListener> listener2_; | |
420 }; | |
421 | |
422 class MockListenerDelegate : public MDnsListener::Delegate { | |
423 public: | |
424 MOCK_METHOD2(OnRecordUpdate, | |
425 void(MDnsListener::UpdateType update, | |
426 const RecordParsed* records)); | |
427 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned)); | |
428 MOCK_METHOD0(OnCachePurged, void()); | |
429 }; | |
430 | |
431 void MDnsTest::SetUp() { | |
432 test_client_.StartListening(&socket_factory_); | |
433 } | |
434 | |
435 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) { | |
436 socket_factory_.SimulateReceive(packet, size); | |
437 } | |
438 | |
439 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) { | |
440 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size))) | |
441 .Times(2); | |
442 } | |
443 | |
444 void MDnsTest::DeleteTransaction() { | |
445 transaction_.reset(); | |
446 } | |
447 | |
448 void MDnsTest::DeleteBothListeners() { | |
449 listener1_.reset(); | |
450 listener2_.reset(); | |
451 } | |
452 | |
453 void MDnsTest::RunFor(base::TimeDelta time_period) { | |
454 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop, | |
455 base::Unretained(this))); | |
456 base::MessageLoop::current()->PostDelayedTask( | |
457 FROM_HERE, callback.callback(), time_period); | |
458 | |
459 base::MessageLoop::current()->Run(); | |
460 callback.Cancel(); | |
461 } | |
462 | |
463 void MDnsTest::Stop() { | |
464 base::MessageLoop::current()->Quit(); | |
465 } | |
466 | |
467 TEST_F(MDnsTest, PassiveListeners) { | |
468 StrictMock<MockListenerDelegate> delegate_privet; | |
469 StrictMock<MockListenerDelegate> delegate_printer; | |
470 | |
471 PtrRecordCopyContainer record_privet; | |
472 PtrRecordCopyContainer record_printer; | |
473 | |
474 scoped_ptr<MDnsListener> listener_privet = | |
475 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
476 &delegate_privet); | |
477 scoped_ptr<MDnsListener> listener_printer = | |
478 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", | |
479 &delegate_printer); | |
480 | |
481 ASSERT_TRUE(listener_privet->Start()); | |
482 ASSERT_TRUE(listener_printer->Start()); | |
483 | |
484 // Send the same packet twice to ensure no records are double-counted. | |
485 | |
486 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
487 .Times(Exactly(1)) | |
488 .WillOnce(Invoke( | |
489 &record_privet, | |
490 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
491 | |
492 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
493 .Times(Exactly(1)) | |
494 .WillOnce(Invoke( | |
495 &record_printer, | |
496 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
497 | |
498 | |
499 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
500 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
501 | |
502 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
503 "hello._privet._tcp.local")); | |
504 | |
505 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local", | |
506 "hello._printer._tcp.local")); | |
507 | |
508 listener_privet.reset(); | |
509 listener_printer.reset(); | |
510 } | |
511 | |
512 TEST_F(MDnsTest, PassiveListenersCacheCleanup) { | |
513 StrictMock<MockListenerDelegate> delegate_privet; | |
514 | |
515 PtrRecordCopyContainer record_privet; | |
516 PtrRecordCopyContainer record_privet2; | |
517 | |
518 scoped_ptr<MDnsListener> listener_privet = | |
519 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
520 &delegate_privet); | |
521 | |
522 ASSERT_TRUE(listener_privet->Start()); | |
523 | |
524 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
525 .Times(Exactly(1)) | |
526 .WillOnce(Invoke( | |
527 &record_privet, | |
528 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
529 | |
530 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
531 | |
532 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
533 "hello._privet._tcp.local")); | |
534 | |
535 // Expect record is removed when its TTL expires. | |
536 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) | |
537 .Times(Exactly(1)) | |
538 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop), | |
539 Invoke(&record_privet2, | |
540 &PtrRecordCopyContainer::SaveWithDummyArg))); | |
541 | |
542 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1)); | |
543 | |
544 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local", | |
545 "hello._privet._tcp.local")); | |
546 } | |
547 | |
548 TEST_F(MDnsTest, MalformedPacket) { | |
549 StrictMock<MockListenerDelegate> delegate_printer; | |
550 | |
551 PtrRecordCopyContainer record_printer; | |
552 | |
553 scoped_ptr<MDnsListener> listener_printer = | |
554 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", | |
555 &delegate_printer); | |
556 | |
557 ASSERT_TRUE(listener_printer->Start()); | |
558 | |
559 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
560 .Times(Exactly(1)) | |
561 .WillOnce(Invoke( | |
562 &record_printer, | |
563 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
564 | |
565 // First, send unsalvagable packet to ensure we can deal with it. | |
566 SimulatePacketReceive(kCorruptedPacketUnsalvagable, | |
567 sizeof(kCorruptedPacketUnsalvagable)); | |
568 | |
569 // Regression test: send a packet where the question cannot be read. | |
570 SimulatePacketReceive(kCorruptedPacketBadQuestion, | |
571 sizeof(kCorruptedPacketBadQuestion)); | |
572 | |
573 // Then send salvagable packet to ensure we can extract useful records. | |
574 SimulatePacketReceive(kCorruptedPacketSalvagable, | |
575 sizeof(kCorruptedPacketSalvagable)); | |
576 | |
577 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local", | |
578 "hello._printer._tcp.local")); | |
579 } | |
580 | |
581 TEST_F(MDnsTest, TransactionWithEmptyCache) { | |
582 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
583 | |
584 scoped_ptr<MDnsTransaction> transaction_privet = | |
585 test_client_.CreateTransaction( | |
586 dns_protocol::kTypePTR, "_privet._tcp.local", | |
587 MDnsTransaction::QUERY_NETWORK | | |
588 MDnsTransaction::QUERY_CACHE | | |
589 MDnsTransaction::SINGLE_RESULT, | |
590 base::Bind(&MDnsTest::MockableRecordCallback, | |
591 base::Unretained(this))); | |
592 | |
593 ASSERT_TRUE(transaction_privet->Start()); | |
594 | |
595 PtrRecordCopyContainer record_privet; | |
596 | |
597 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) | |
598 .Times(Exactly(1)) | |
599 .WillOnce(Invoke(&record_privet, | |
600 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
601 | |
602 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
603 | |
604 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
605 "hello._privet._tcp.local")); | |
606 } | |
607 | |
608 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) { | |
609 scoped_ptr<MDnsTransaction> transaction_privet = | |
610 test_client_.CreateTransaction( | |
611 dns_protocol::kTypePTR, "_privet._tcp.local", | |
612 MDnsTransaction::QUERY_CACHE | | |
613 MDnsTransaction::SINGLE_RESULT, | |
614 base::Bind(&MDnsTest::MockableRecordCallback, | |
615 base::Unretained(this))); | |
616 | |
617 EXPECT_CALL(*this, | |
618 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _)) | |
619 .Times(Exactly(1)); | |
620 | |
621 ASSERT_TRUE(transaction_privet->Start()); | |
622 } | |
623 | |
624 TEST_F(MDnsTest, TransactionWithCache) { | |
625 // Listener to force the client to listen | |
626 StrictMock<MockListenerDelegate> delegate_irrelevant; | |
627 scoped_ptr<MDnsListener> listener_irrelevant = | |
628 test_client_.CreateListener(dns_protocol::kTypeA, | |
629 "codereview.chromium.local", | |
630 &delegate_irrelevant); | |
631 | |
632 ASSERT_TRUE(listener_irrelevant->Start()); | |
633 | |
634 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
635 | |
636 | |
637 PtrRecordCopyContainer record_privet; | |
638 | |
639 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) | |
640 .WillOnce(Invoke(&record_privet, | |
641 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
642 | |
643 scoped_ptr<MDnsTransaction> transaction_privet = | |
644 test_client_.CreateTransaction( | |
645 dns_protocol::kTypePTR, "_privet._tcp.local", | |
646 MDnsTransaction::QUERY_NETWORK | | |
647 MDnsTransaction::QUERY_CACHE | | |
648 MDnsTransaction::SINGLE_RESULT, | |
649 base::Bind(&MDnsTest::MockableRecordCallback, | |
650 base::Unretained(this))); | |
651 | |
652 ASSERT_TRUE(transaction_privet->Start()); | |
653 | |
654 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
655 "hello._privet._tcp.local")); | |
656 } | |
657 | |
658 TEST_F(MDnsTest, AdditionalRecords) { | |
659 StrictMock<MockListenerDelegate> delegate_privet; | |
660 | |
661 PtrRecordCopyContainer record_privet; | |
662 | |
663 scoped_ptr<MDnsListener> listener_privet = | |
664 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
665 &delegate_privet); | |
666 | |
667 ASSERT_TRUE(listener_privet->Start()); | |
668 | |
669 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
670 .Times(Exactly(1)) | |
671 .WillOnce(Invoke( | |
672 &record_privet, | |
673 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
674 | |
675 SimulatePacketReceive(kSamplePacketAdditionalOnly, | |
676 sizeof(kSamplePacketAdditionalOnly)); | |
677 | |
678 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
679 "hello._privet._tcp.local")); | |
680 } | |
681 | |
682 TEST_F(MDnsTest, TransactionTimeout) { | |
683 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
684 | |
685 scoped_ptr<MDnsTransaction> transaction_privet = | |
686 test_client_.CreateTransaction( | |
687 dns_protocol::kTypePTR, "_privet._tcp.local", | |
688 MDnsTransaction::QUERY_NETWORK | | |
689 MDnsTransaction::QUERY_CACHE | | |
690 MDnsTransaction::SINGLE_RESULT, | |
691 base::Bind(&MDnsTest::MockableRecordCallback, | |
692 base::Unretained(this))); | |
693 | |
694 ASSERT_TRUE(transaction_privet->Start()); | |
695 | |
696 EXPECT_CALL(*this, | |
697 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL)) | |
698 .Times(Exactly(1)) | |
699 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop)); | |
700 | |
701 RunFor(base::TimeDelta::FromSeconds(4)); | |
702 } | |
703 | |
704 TEST_F(MDnsTest, TransactionMultipleRecords) { | |
705 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
706 | |
707 scoped_ptr<MDnsTransaction> transaction_privet = | |
708 test_client_.CreateTransaction( | |
709 dns_protocol::kTypePTR, "_privet._tcp.local", | |
710 MDnsTransaction::QUERY_NETWORK | | |
711 MDnsTransaction::QUERY_CACHE , | |
712 base::Bind(&MDnsTest::MockableRecordCallback, | |
713 base::Unretained(this))); | |
714 | |
715 ASSERT_TRUE(transaction_privet->Start()); | |
716 | |
717 PtrRecordCopyContainer record_privet; | |
718 PtrRecordCopyContainer record_privet2; | |
719 | |
720 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) | |
721 .Times(Exactly(2)) | |
722 .WillOnce(Invoke(&record_privet, | |
723 &PtrRecordCopyContainer::SaveWithDummyArg)) | |
724 .WillOnce(Invoke(&record_privet2, | |
725 &PtrRecordCopyContainer::SaveWithDummyArg)); | |
726 | |
727 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
728 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2)); | |
729 | |
730 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", | |
731 "hello._privet._tcp.local")); | |
732 | |
733 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local", | |
734 "zzzzz._privet._tcp.local")); | |
735 | |
736 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL)) | |
737 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop)); | |
738 | |
739 RunFor(base::TimeDelta::FromSeconds(4)); | |
740 } | |
741 | |
742 TEST_F(MDnsTest, TransactionReentrantDelete) { | |
743 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
744 | |
745 transaction_ = test_client_.CreateTransaction( | |
746 dns_protocol::kTypePTR, "_privet._tcp.local", | |
747 MDnsTransaction::QUERY_NETWORK | | |
748 MDnsTransaction::QUERY_CACHE | | |
749 MDnsTransaction::SINGLE_RESULT, | |
750 base::Bind(&MDnsTest::MockableRecordCallback, | |
751 base::Unretained(this))); | |
752 | |
753 ASSERT_TRUE(transaction_->Start()); | |
754 | |
755 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, | |
756 NULL)) | |
757 .Times(Exactly(1)) | |
758 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction), | |
759 InvokeWithoutArgs(this, &MDnsTest::Stop))); | |
760 | |
761 RunFor(base::TimeDelta::FromSeconds(4)); | |
762 | |
763 EXPECT_EQ(NULL, transaction_.get()); | |
764 } | |
765 | |
766 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) { | |
767 StrictMock<MockListenerDelegate> delegate_irrelevant; | |
768 scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener( | |
769 dns_protocol::kTypeA, "codereview.chromium.local", | |
770 &delegate_irrelevant); | |
771 ASSERT_TRUE(listener_irrelevant->Start()); | |
772 | |
773 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
774 | |
775 transaction_ = test_client_.CreateTransaction( | |
776 dns_protocol::kTypePTR, "_privet._tcp.local", | |
777 MDnsTransaction::QUERY_NETWORK | | |
778 MDnsTransaction::QUERY_CACHE, | |
779 base::Bind(&MDnsTest::MockableRecordCallback, | |
780 base::Unretained(this))); | |
781 | |
782 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) | |
783 .Times(Exactly(1)) | |
784 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction)); | |
785 | |
786 ASSERT_TRUE(transaction_->Start()); | |
787 | |
788 EXPECT_EQ(NULL, transaction_.get()); | |
789 } | |
790 | |
791 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) { | |
792 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
793 | |
794 scoped_ptr<MDnsTransaction> transaction1 = | |
795 test_client_.CreateTransaction( | |
796 dns_protocol::kTypePTR, "_privet._tcp.local", | |
797 MDnsTransaction::QUERY_NETWORK | | |
798 MDnsTransaction::QUERY_CACHE | | |
799 MDnsTransaction::SINGLE_RESULT, | |
800 base::Bind(&MDnsTest::MockableRecordCallback, | |
801 base::Unretained(this))); | |
802 | |
803 scoped_ptr<MDnsTransaction> transaction2 = | |
804 test_client_.CreateTransaction( | |
805 dns_protocol::kTypePTR, "_printer._tcp.local", | |
806 MDnsTransaction::QUERY_CACHE | | |
807 MDnsTransaction::SINGLE_RESULT, | |
808 base::Bind(&MDnsTest::MockableRecordCallback2, | |
809 base::Unretained(this))); | |
810 | |
811 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD, | |
812 _)) | |
813 .Times(Exactly(1)); | |
814 | |
815 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, | |
816 _)) | |
817 .Times(Exactly(1)) | |
818 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(), | |
819 &MDnsTransaction::Start))); | |
820 | |
821 ASSERT_TRUE(transaction1->Start()); | |
822 | |
823 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
824 } | |
825 | |
826 TEST_F(MDnsTest, GoodbyePacketNotification) { | |
827 StrictMock<MockListenerDelegate> delegate_privet; | |
828 | |
829 scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener( | |
830 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); | |
831 ASSERT_TRUE(listener_privet->Start()); | |
832 | |
833 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye)); | |
834 | |
835 RunFor(base::TimeDelta::FromSeconds(2)); | |
836 } | |
837 | |
838 TEST_F(MDnsTest, GoodbyePacketRemoval) { | |
839 StrictMock<MockListenerDelegate> delegate_privet; | |
840 | |
841 scoped_ptr<MDnsListener> listener_privet = | |
842 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
843 &delegate_privet); | |
844 ASSERT_TRUE(listener_privet->Start()); | |
845 | |
846 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
847 .Times(Exactly(1)); | |
848 | |
849 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2)); | |
850 | |
851 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye)); | |
852 | |
853 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) | |
854 .Times(Exactly(1)); | |
855 | |
856 RunFor(base::TimeDelta::FromSeconds(2)); | |
857 } | |
858 | |
859 // In order to reliably test reentrant listener deletes, we create two listeners | |
860 // and have each of them delete both, so we're guaranteed to try and deliver a | |
861 // callback to at least one deleted listener. | |
862 | |
863 TEST_F(MDnsTest, ListenerReentrantDelete) { | |
864 StrictMock<MockListenerDelegate> delegate_privet; | |
865 | |
866 listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR, | |
867 "_privet._tcp.local", | |
868 &delegate_privet); | |
869 | |
870 listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR, | |
871 "_privet._tcp.local", | |
872 &delegate_privet); | |
873 | |
874 ASSERT_TRUE(listener1_->Start()); | |
875 | |
876 ASSERT_TRUE(listener2_->Start()); | |
877 | |
878 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
879 .Times(Exactly(1)) | |
880 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners)); | |
881 | |
882 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); | |
883 | |
884 EXPECT_EQ(NULL, listener1_.get()); | |
885 EXPECT_EQ(NULL, listener2_.get()); | |
886 } | |
887 | |
888 ACTION_P(SaveIPAddress, ip_container) { | |
889 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>(); | |
890 ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>(); | |
891 | |
892 *ip_container = arg1->template rdata<ARecordRdata>()->address(); | |
893 } | |
894 | |
895 TEST_F(MDnsTest, DoubleRecordDisagreeing) { | |
896 IPAddressNumber address; | |
897 StrictMock<MockListenerDelegate> delegate_privet; | |
898 | |
899 scoped_ptr<MDnsListener> listener_privet = | |
900 test_client_.CreateListener(dns_protocol::kTypeA, "privet.local", | |
901 &delegate_privet); | |
902 | |
903 ASSERT_TRUE(listener_privet->Start()); | |
904 | |
905 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
906 .Times(Exactly(1)) | |
907 .WillOnce(SaveIPAddress(&address)); | |
908 | |
909 SimulatePacketReceive(kCorruptedPacketDoubleRecord, | |
910 sizeof(kCorruptedPacketDoubleRecord)); | |
911 | |
912 EXPECT_EQ("2.3.4.5", IPAddressToString(address)); | |
913 } | |
914 | |
915 TEST_F(MDnsTest, NsecWithListener) { | |
916 StrictMock<MockListenerDelegate> delegate_privet; | |
917 scoped_ptr<MDnsListener> listener_privet = | |
918 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", | |
919 &delegate_privet); | |
920 | |
921 // Test to make sure nsec callback is NOT called for PTR | |
922 // (which is marked as existing). | |
923 StrictMock<MockListenerDelegate> delegate_privet2; | |
924 scoped_ptr<MDnsListener> listener_privet2 = | |
925 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
926 &delegate_privet2); | |
927 | |
928 ASSERT_TRUE(listener_privet->Start()); | |
929 | |
930 EXPECT_CALL(delegate_privet, | |
931 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA)); | |
932 | |
933 SimulatePacketReceive(kSamplePacketNsec, | |
934 sizeof(kSamplePacketNsec)); | |
935 } | |
936 | |
937 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) { | |
938 scoped_ptr<MDnsTransaction> transaction_privet = | |
939 test_client_.CreateTransaction( | |
940 dns_protocol::kTypeA, "_privet._tcp.local", | |
941 MDnsTransaction::QUERY_NETWORK | | |
942 MDnsTransaction::QUERY_CACHE | | |
943 MDnsTransaction::SINGLE_RESULT, | |
944 base::Bind(&MDnsTest::MockableRecordCallback, | |
945 base::Unretained(this))); | |
946 | |
947 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2); | |
948 | |
949 ASSERT_TRUE(transaction_privet->Start()); | |
950 | |
951 EXPECT_CALL(*this, | |
952 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL)); | |
953 | |
954 SimulatePacketReceive(kSamplePacketNsec, | |
955 sizeof(kSamplePacketNsec)); | |
956 } | |
957 | |
958 TEST_F(MDnsTest, NsecWithTransactionFromCache) { | |
959 // Force mDNS to listen. | |
960 StrictMock<MockListenerDelegate> delegate_irrelevant; | |
961 scoped_ptr<MDnsListener> listener_irrelevant = | |
962 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", | |
963 &delegate_irrelevant); | |
964 listener_irrelevant->Start(); | |
965 | |
966 SimulatePacketReceive(kSamplePacketNsec, | |
967 sizeof(kSamplePacketNsec)); | |
968 | |
969 EXPECT_CALL(*this, | |
970 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL)); | |
971 | |
972 scoped_ptr<MDnsTransaction> transaction_privet_a = | |
973 test_client_.CreateTransaction( | |
974 dns_protocol::kTypeA, "_privet._tcp.local", | |
975 MDnsTransaction::QUERY_NETWORK | | |
976 MDnsTransaction::QUERY_CACHE | | |
977 MDnsTransaction::SINGLE_RESULT, | |
978 base::Bind(&MDnsTest::MockableRecordCallback, | |
979 base::Unretained(this))); | |
980 | |
981 ASSERT_TRUE(transaction_privet_a->Start()); | |
982 | |
983 // Test that a PTR transaction does NOT consider the same NSEC record to be a | |
984 // valid answer to the query | |
985 | |
986 scoped_ptr<MDnsTransaction> transaction_privet_ptr = | |
987 test_client_.CreateTransaction( | |
988 dns_protocol::kTypePTR, "_privet._tcp.local", | |
989 MDnsTransaction::QUERY_NETWORK | | |
990 MDnsTransaction::QUERY_CACHE | | |
991 MDnsTransaction::SINGLE_RESULT, | |
992 base::Bind(&MDnsTest::MockableRecordCallback, | |
993 base::Unretained(this))); | |
994 | |
995 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2); | |
996 | |
997 ASSERT_TRUE(transaction_privet_ptr->Start()); | |
998 } | |
999 | |
1000 TEST_F(MDnsTest, NsecConflictRemoval) { | |
1001 StrictMock<MockListenerDelegate> delegate_privet; | |
1002 scoped_ptr<MDnsListener> listener_privet = | |
1003 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", | |
1004 &delegate_privet); | |
1005 | |
1006 ASSERT_TRUE(listener_privet->Start()); | |
1007 | |
1008 const RecordParsed* record1; | |
1009 const RecordParsed* record2; | |
1010 | |
1011 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) | |
1012 .WillOnce(SaveArg<1>(&record1)); | |
1013 | |
1014 SimulatePacketReceive(kSamplePacketAPrivet, | |
1015 sizeof(kSamplePacketAPrivet)); | |
1016 | |
1017 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) | |
1018 .WillOnce(SaveArg<1>(&record2)); | |
1019 | |
1020 EXPECT_CALL(delegate_privet, | |
1021 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA)); | |
1022 | |
1023 SimulatePacketReceive(kSamplePacketNsec, | |
1024 sizeof(kSamplePacketNsec)); | |
1025 | |
1026 EXPECT_EQ(record1, record2); | |
1027 } | |
1028 | |
1029 | |
1030 TEST_F(MDnsTest, RefreshQuery) { | |
1031 StrictMock<MockListenerDelegate> delegate_privet; | |
1032 scoped_ptr<MDnsListener> listener_privet = | |
1033 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", | |
1034 &delegate_privet); | |
1035 | |
1036 listener_privet->SetActiveRefresh(true); | |
1037 ASSERT_TRUE(listener_privet->Start()); | |
1038 | |
1039 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)); | |
1040 | |
1041 SimulatePacketReceive(kSamplePacketAPrivet, | |
1042 sizeof(kSamplePacketAPrivet)); | |
1043 | |
1044 // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2 | |
1045 // scheduled refresh queries. | |
1046 EXPECT_CALL(socket_factory_, OnSendTo( | |
1047 MakeString(kQueryPacketPrivetA, sizeof(kQueryPacketPrivetA)))) | |
1048 .Times(4); | |
1049 | |
1050 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)); | |
1051 | |
1052 RunFor(base::TimeDelta::FromSeconds(6)); | |
1053 } | |
1054 | |
1055 // Note: These tests assume that the ipv4 socket will always be created first. | |
1056 // This is a simplifying assumption based on the way the code works now. | |
1057 class SimpleMockSocketFactory : public MDnsSocketFactory { | |
1058 public: | |
1059 void CreateSockets(ScopedVector<DatagramServerSocket>* sockets) override { | |
1060 sockets->clear(); | |
1061 sockets->swap(sockets_); | |
1062 } | |
1063 | |
1064 void PushSocket(DatagramServerSocket* socket) { | |
1065 sockets_.push_back(socket); | |
1066 } | |
1067 | |
1068 private: | |
1069 ScopedVector<DatagramServerSocket> sockets_; | |
1070 }; | |
1071 | |
1072 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate { | |
1073 public: | |
1074 virtual void HandlePacket(DnsResponse* response, int size) { | |
1075 HandlePacketInternal(std::string(response->io_buffer()->data(), size)); | |
1076 } | |
1077 | |
1078 MOCK_METHOD1(HandlePacketInternal, void(std::string packet)); | |
1079 | |
1080 MOCK_METHOD1(OnConnectionError, void(int error)); | |
1081 }; | |
1082 | |
1083 class MDnsConnectionTest : public ::testing::Test { | |
1084 public: | |
1085 MDnsConnectionTest() : connection_(&delegate_) { | |
1086 } | |
1087 | |
1088 protected: | |
1089 // Follow successful connection initialization. | |
1090 virtual void SetUp() override { | |
1091 socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4); | |
1092 socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6); | |
1093 factory_.PushSocket(socket_ipv6_); | |
1094 factory_.PushSocket(socket_ipv4_); | |
1095 sample_packet_ = MakeString(kSamplePacket1, sizeof(kSamplePacket1)); | |
1096 sample_buffer_ = new StringIOBuffer(sample_packet_); | |
1097 } | |
1098 | |
1099 bool InitConnection() { | |
1100 return connection_.Init(&factory_); | |
1101 } | |
1102 | |
1103 StrictMock<MockMDnsConnectionDelegate> delegate_; | |
1104 | |
1105 MockMDnsDatagramServerSocket* socket_ipv4_; | |
1106 MockMDnsDatagramServerSocket* socket_ipv6_; | |
1107 SimpleMockSocketFactory factory_; | |
1108 MDnsConnection connection_; | |
1109 TestCompletionCallback callback_; | |
1110 std::string sample_packet_; | |
1111 scoped_refptr<IOBuffer> sample_buffer_; | |
1112 }; | |
1113 | |
1114 TEST_F(MDnsConnectionTest, ReceiveSynchronous) { | |
1115 socket_ipv6_->SetResponsePacket(sample_packet_); | |
1116 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) | |
1117 .WillOnce(Return(ERR_IO_PENDING)); | |
1118 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) | |
1119 .WillOnce( | |
1120 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow)) | |
1121 .WillOnce(Return(ERR_IO_PENDING)); | |
1122 | |
1123 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_)); | |
1124 ASSERT_TRUE(InitConnection()); | |
1125 } | |
1126 | |
1127 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) { | |
1128 socket_ipv6_->SetResponsePacket(sample_packet_); | |
1129 | |
1130 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) | |
1131 .WillOnce(Return(ERR_IO_PENDING)); | |
1132 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) | |
1133 .Times(2) | |
1134 .WillOnce( | |
1135 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater)) | |
1136 .WillOnce(Return(ERR_IO_PENDING)); | |
1137 | |
1138 ASSERT_TRUE(InitConnection()); | |
1139 | |
1140 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_)); | |
1141 | |
1142 base::MessageLoop::current()->RunUntilIdle(); | |
1143 } | |
1144 | |
1145 TEST_F(MDnsConnectionTest, Error) { | |
1146 CompletionCallback callback; | |
1147 | |
1148 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) | |
1149 .WillOnce(Return(ERR_IO_PENDING)); | |
1150 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) | |
1151 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING))); | |
1152 | |
1153 ASSERT_TRUE(InitConnection()); | |
1154 | |
1155 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED)); | |
1156 callback.Run(ERR_SOCKET_NOT_CONNECTED); | |
1157 base::MessageLoop::current()->RunUntilIdle(); | |
1158 } | |
1159 | |
1160 class MDnsConnectionSendTest : public MDnsConnectionTest { | |
1161 protected: | |
1162 void SetUp() override { | |
1163 MDnsConnectionTest::SetUp(); | |
1164 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) | |
1165 .WillOnce(Return(ERR_IO_PENDING)); | |
1166 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) | |
1167 .WillOnce(Return(ERR_IO_PENDING)); | |
1168 EXPECT_TRUE(InitConnection()); | |
1169 } | |
1170 }; | |
1171 | |
1172 TEST_F(MDnsConnectionSendTest, Send) { | |
1173 EXPECT_CALL(*socket_ipv4_, | |
1174 SendToInternal(sample_packet_, "224.0.0.251:5353", _)); | |
1175 EXPECT_CALL(*socket_ipv6_, | |
1176 SendToInternal(sample_packet_, "[ff02::fb]:5353", _)); | |
1177 | |
1178 connection_.Send(sample_buffer_, sample_packet_.size()); | |
1179 } | |
1180 | |
1181 TEST_F(MDnsConnectionSendTest, SendError) { | |
1182 CompletionCallback callback; | |
1183 | |
1184 EXPECT_CALL(*socket_ipv4_, | |
1185 SendToInternal(sample_packet_, "224.0.0.251:5353", _)); | |
1186 EXPECT_CALL(*socket_ipv6_, | |
1187 SendToInternal(sample_packet_, "[ff02::fb]:5353", _)) | |
1188 .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_SOCKET_NOT_CONNECTED))); | |
1189 | |
1190 connection_.Send(sample_buffer_, sample_packet_.size()); | |
1191 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED)); | |
1192 base::MessageLoop::current()->RunUntilIdle(); | |
1193 } | |
1194 | |
1195 TEST_F(MDnsConnectionSendTest, SendQueued) { | |
1196 // Send data immediately. | |
1197 EXPECT_CALL(*socket_ipv4_, | |
1198 SendToInternal(sample_packet_, "224.0.0.251:5353", _)) | |
1199 .Times(2) | |
1200 .WillRepeatedly(Return(OK)); | |
1201 | |
1202 CompletionCallback callback; | |
1203 // Delay sending data. Only the first call should be made. | |
1204 EXPECT_CALL(*socket_ipv6_, | |
1205 SendToInternal(sample_packet_, "[ff02::fb]:5353", _)) | |
1206 .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_IO_PENDING))); | |
1207 | |
1208 connection_.Send(sample_buffer_, sample_packet_.size()); | |
1209 connection_.Send(sample_buffer_, sample_packet_.size()); | |
1210 | |
1211 // The second IPv6 packed is not sent yet. | |
1212 EXPECT_CALL(*socket_ipv4_, | |
1213 SendToInternal(sample_packet_, "224.0.0.251:5353", _)) | |
1214 .Times(0); | |
1215 // Expect call for the second IPv6 packed. | |
1216 EXPECT_CALL(*socket_ipv6_, | |
1217 SendToInternal(sample_packet_, "[ff02::fb]:5353", _)) | |
1218 .WillOnce(Return(OK)); | |
1219 callback.Run(OK); | |
1220 } | |
1221 | |
1222 } // namespace | |
1223 | |
1224 } // namespace net | |
OLD | NEW |