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 kSamplePacketAdditionalOnly[] = {
245 // Header
246 0x00, 0x00, // ID is zeroed out
247 0x81, 0x80, // Standard query response, RA, no error
248 0x00, 0x00, // No questions (for simplicity)
249 0x00, 0x00, // 2 RRs (answers)
250 0x00, 0x00, // 0 authority RRs
251 0x00, 0x01, // 0 additional RRs
252
253 // Answer 1
254 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
255 0x04, '_', 't', 'c', 'p',
256 0x05, 'l', 'o', 'c', 'a', 'l',
257 0x00,
258 0x00, 0x0c, // TYPE is PTR.
259 0x00, 0x01, // CLASS is IN.
260 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
261 0x24, 0x74,
262 0x00, 0x08, // RDLENGTH is 8 bytes.
263 0x05, 'h', 'e', 'l', 'l', 'o',
264 0xc0, 0x0c,
265 };
266
267 const uint8 kSamplePacketNsec[] = {
268 // Header
269 0x00, 0x00, // ID is zeroed out
270 0x81, 0x80, // Standard query response, RA, no error
271 0x00, 0x00, // No questions (for simplicity)
272 0x00, 0x01, // 1 RR (answers)
273 0x00, 0x00, // 0 authority RRs
274 0x00, 0x00, // 0 additional RRs
275
276 // Answer 1
277 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
278 0x04, '_', 't', 'c', 'p',
279 0x05, 'l', 'o', 'c', 'a', 'l',
280 0x00,
281 0x00, 0x2f, // TYPE is NSEC.
282 0x00, 0x01, // CLASS is IN.
283 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
284 0x24, 0x74,
285 0x00, 0x06, // RDLENGTH is 6 bytes.
286 0xc0, 0x0c,
287 0x00, 0x02, 0x00, 0x08 // Only A record present
288 };
289
290 const uint8 kSamplePacketAPrivet[] = {
291 // Header
292 0x00, 0x00, // ID is zeroed out
293 0x81, 0x80, // Standard query response, RA, no error
294 0x00, 0x00, // No questions (for simplicity)
295 0x00, 0x01, // 1 RR (answers)
296 0x00, 0x00, // 0 authority RRs
297 0x00, 0x00, // 0 additional RRs
298
299 // Answer 1
300 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
301 0x04, '_', 't', 'c', 'p',
302 0x05, 'l', 'o', 'c', 'a', 'l',
303 0x00,
304 0x00, 0x01, // TYPE is A.
305 0x00, 0x01, // CLASS is IN.
306 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
307 0x24, 0x74,
308 0x00, 0x04, // RDLENGTH is 4 bytes.
309 0xc0, 0x0c,
310 0x00, 0x02,
311 };
312
313 const uint8 kSamplePacketGoodbye[] = {
314 // Header
315 0x00, 0x00, // ID is zeroed out
316 0x81, 0x80, // Standard query response, RA, no error
317 0x00, 0x00, // No questions (for simplicity)
318 0x00, 0x01, // 2 RRs (answers)
319 0x00, 0x00, // 0 authority RRs
320 0x00, 0x00, // 0 additional RRs
321
322 // Answer 1
323 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
324 0x04, '_', 't', 'c', 'p',
325 0x05, 'l', 'o', 'c', 'a', 'l',
326 0x00,
327 0x00, 0x0c, // TYPE is PTR.
328 0x00, 0x01, // CLASS is IN.
329 0x00, 0x00, // TTL (4 bytes) is zero;
330 0x00, 0x00,
331 0x00, 0x08, // RDLENGTH is 8 bytes.
332 0x05, 'z', 'z', 'z', 'z', 'z',
333 0xc0, 0x0c,
334 };
335
MakeString(const uint8 * data,unsigned size)336 std::string MakeString(const uint8* data, unsigned size) {
337 return std::string(reinterpret_cast<const char*>(data), size);
338 }
339
340 class PtrRecordCopyContainer {
341 public:
PtrRecordCopyContainer()342 PtrRecordCopyContainer() {}
~PtrRecordCopyContainer()343 ~PtrRecordCopyContainer() {}
344
is_set() const345 bool is_set() const { return set_; }
346
SaveWithDummyArg(int unused,const RecordParsed * value)347 void SaveWithDummyArg(int unused, const RecordParsed* value) {
348 Save(value);
349 }
350
Save(const RecordParsed * value)351 void Save(const RecordParsed* value) {
352 set_ = true;
353 name_ = value->name();
354 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
355 ttl_ = value->ttl();
356 }
357
IsRecordWith(std::string name,std::string ptrdomain)358 bool IsRecordWith(std::string name, std::string ptrdomain) {
359 return set_ && name_ == name && ptrdomain_ == ptrdomain;
360 }
361
name()362 const std::string& name() { return name_; }
ptrdomain()363 const std::string& ptrdomain() { return ptrdomain_; }
ttl()364 int ttl() { return ttl_; }
365
366 private:
367 bool set_;
368 std::string name_;
369 std::string ptrdomain_;
370 int ttl_;
371 };
372
373 class MDnsTest : public ::testing::Test {
374 public:
375 virtual void SetUp() OVERRIDE;
376 void DeleteTransaction();
377 void DeleteBothListeners();
378 void RunFor(base::TimeDelta time_period);
379 void Stop();
380
381 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
382 const RecordParsed* record));
383
384 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
385 const RecordParsed* record));
386
387
388 protected:
389 void ExpectPacket(const uint8* packet, unsigned size);
390 void SimulatePacketReceive(const uint8* packet, unsigned size);
391
392 MDnsClientImpl test_client_;
393 IPEndPoint mdns_ipv4_endpoint_;
394 StrictMock<MockMDnsSocketFactory> socket_factory_;
395
396 // Transactions and listeners that can be deleted by class methods for
397 // reentrancy tests.
398 scoped_ptr<MDnsTransaction> transaction_;
399 scoped_ptr<MDnsListener> listener1_;
400 scoped_ptr<MDnsListener> listener2_;
401 };
402
403 class MockListenerDelegate : public MDnsListener::Delegate {
404 public:
405 MOCK_METHOD2(OnRecordUpdate,
406 void(MDnsListener::UpdateType update,
407 const RecordParsed* records));
408 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
409 MOCK_METHOD0(OnCachePurged, void());
410 };
411
SetUp()412 void MDnsTest::SetUp() {
413 test_client_.StartListening(&socket_factory_);
414 }
415
SimulatePacketReceive(const uint8 * packet,unsigned size)416 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
417 socket_factory_.SimulateReceive(packet, size);
418 }
419
ExpectPacket(const uint8 * packet,unsigned size)420 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
421 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
422 .Times(2);
423 }
424
DeleteTransaction()425 void MDnsTest::DeleteTransaction() {
426 transaction_.reset();
427 }
428
DeleteBothListeners()429 void MDnsTest::DeleteBothListeners() {
430 listener1_.reset();
431 listener2_.reset();
432 }
433
RunFor(base::TimeDelta time_period)434 void MDnsTest::RunFor(base::TimeDelta time_period) {
435 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
436 base::Unretained(this)));
437 base::MessageLoop::current()->PostDelayedTask(
438 FROM_HERE, callback.callback(), time_period);
439
440 base::MessageLoop::current()->Run();
441 callback.Cancel();
442 }
443
Stop()444 void MDnsTest::Stop() {
445 base::MessageLoop::current()->Quit();
446 }
447
TEST_F(MDnsTest,PassiveListeners)448 TEST_F(MDnsTest, PassiveListeners) {
449 StrictMock<MockListenerDelegate> delegate_privet;
450 StrictMock<MockListenerDelegate> delegate_printer;
451
452 PtrRecordCopyContainer record_privet;
453 PtrRecordCopyContainer record_printer;
454
455 scoped_ptr<MDnsListener> listener_privet =
456 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
457 &delegate_privet);
458 scoped_ptr<MDnsListener> listener_printer =
459 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
460 &delegate_printer);
461
462 ASSERT_TRUE(listener_privet->Start());
463 ASSERT_TRUE(listener_printer->Start());
464
465 // Send the same packet twice to ensure no records are double-counted.
466
467 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
468 .Times(Exactly(1))
469 .WillOnce(Invoke(
470 &record_privet,
471 &PtrRecordCopyContainer::SaveWithDummyArg));
472
473 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
474 .Times(Exactly(1))
475 .WillOnce(Invoke(
476 &record_printer,
477 &PtrRecordCopyContainer::SaveWithDummyArg));
478
479
480 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
481 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
482
483 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
484 "hello._privet._tcp.local"));
485
486 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
487 "hello._printer._tcp.local"));
488
489 listener_privet.reset();
490 listener_printer.reset();
491 }
492
TEST_F(MDnsTest,PassiveListenersCacheCleanup)493 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
494 StrictMock<MockListenerDelegate> delegate_privet;
495
496 PtrRecordCopyContainer record_privet;
497 PtrRecordCopyContainer record_privet2;
498
499 scoped_ptr<MDnsListener> listener_privet =
500 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
501 &delegate_privet);
502
503 ASSERT_TRUE(listener_privet->Start());
504
505 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
506 .Times(Exactly(1))
507 .WillOnce(Invoke(
508 &record_privet,
509 &PtrRecordCopyContainer::SaveWithDummyArg));
510
511 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
512
513 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
514 "hello._privet._tcp.local"));
515
516 // Expect record is removed when its TTL expires.
517 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
518 .Times(Exactly(1))
519 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
520 Invoke(&record_privet2,
521 &PtrRecordCopyContainer::SaveWithDummyArg)));
522
523 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
524
525 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
526 "hello._privet._tcp.local"));
527 }
528
TEST_F(MDnsTest,MalformedPacket)529 TEST_F(MDnsTest, MalformedPacket) {
530 StrictMock<MockListenerDelegate> delegate_printer;
531
532 PtrRecordCopyContainer record_printer;
533
534 scoped_ptr<MDnsListener> listener_printer =
535 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
536 &delegate_printer);
537
538 ASSERT_TRUE(listener_printer->Start());
539
540 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
541 .Times(Exactly(1))
542 .WillOnce(Invoke(
543 &record_printer,
544 &PtrRecordCopyContainer::SaveWithDummyArg));
545
546 // First, send unsalvagable packet to ensure we can deal with it.
547 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
548 sizeof(kCorruptedPacketUnsalvagable));
549
550 // Regression test: send a packet where the question cannot be read.
551 SimulatePacketReceive(kCorruptedPacketBadQuestion,
552 sizeof(kCorruptedPacketBadQuestion));
553
554 // Then send salvagable packet to ensure we can extract useful records.
555 SimulatePacketReceive(kCorruptedPacketSalvagable,
556 sizeof(kCorruptedPacketSalvagable));
557
558 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
559 "hello._printer._tcp.local"));
560 }
561
TEST_F(MDnsTest,TransactionWithEmptyCache)562 TEST_F(MDnsTest, TransactionWithEmptyCache) {
563 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
564
565 scoped_ptr<MDnsTransaction> transaction_privet =
566 test_client_.CreateTransaction(
567 dns_protocol::kTypePTR, "_privet._tcp.local",
568 MDnsTransaction::QUERY_NETWORK |
569 MDnsTransaction::QUERY_CACHE |
570 MDnsTransaction::SINGLE_RESULT,
571 base::Bind(&MDnsTest::MockableRecordCallback,
572 base::Unretained(this)));
573
574 ASSERT_TRUE(transaction_privet->Start());
575
576 PtrRecordCopyContainer record_privet;
577
578 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
579 .Times(Exactly(1))
580 .WillOnce(Invoke(&record_privet,
581 &PtrRecordCopyContainer::SaveWithDummyArg));
582
583 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
584
585 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
586 "hello._privet._tcp.local"));
587 }
588
TEST_F(MDnsTest,TransactionCacheOnlyNoResult)589 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
590 scoped_ptr<MDnsTransaction> transaction_privet =
591 test_client_.CreateTransaction(
592 dns_protocol::kTypePTR, "_privet._tcp.local",
593 MDnsTransaction::QUERY_CACHE |
594 MDnsTransaction::SINGLE_RESULT,
595 base::Bind(&MDnsTest::MockableRecordCallback,
596 base::Unretained(this)));
597
598 EXPECT_CALL(*this,
599 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
600 .Times(Exactly(1));
601
602 ASSERT_TRUE(transaction_privet->Start());
603 }
604
TEST_F(MDnsTest,TransactionWithCache)605 TEST_F(MDnsTest, TransactionWithCache) {
606 // Listener to force the client to listen
607 StrictMock<MockListenerDelegate> delegate_irrelevant;
608 scoped_ptr<MDnsListener> listener_irrelevant =
609 test_client_.CreateListener(dns_protocol::kTypeA,
610 "codereview.chromium.local",
611 &delegate_irrelevant);
612
613 ASSERT_TRUE(listener_irrelevant->Start());
614
615 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
616
617
618 PtrRecordCopyContainer record_privet;
619
620 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
621 .WillOnce(Invoke(&record_privet,
622 &PtrRecordCopyContainer::SaveWithDummyArg));
623
624 scoped_ptr<MDnsTransaction> transaction_privet =
625 test_client_.CreateTransaction(
626 dns_protocol::kTypePTR, "_privet._tcp.local",
627 MDnsTransaction::QUERY_NETWORK |
628 MDnsTransaction::QUERY_CACHE |
629 MDnsTransaction::SINGLE_RESULT,
630 base::Bind(&MDnsTest::MockableRecordCallback,
631 base::Unretained(this)));
632
633 ASSERT_TRUE(transaction_privet->Start());
634
635 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
636 "hello._privet._tcp.local"));
637 }
638
TEST_F(MDnsTest,AdditionalRecords)639 TEST_F(MDnsTest, AdditionalRecords) {
640 StrictMock<MockListenerDelegate> delegate_privet;
641
642 PtrRecordCopyContainer record_privet;
643
644 scoped_ptr<MDnsListener> listener_privet =
645 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
646 &delegate_privet);
647
648 ASSERT_TRUE(listener_privet->Start());
649
650 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
651 .Times(Exactly(1))
652 .WillOnce(Invoke(
653 &record_privet,
654 &PtrRecordCopyContainer::SaveWithDummyArg));
655
656 SimulatePacketReceive(kSamplePacketAdditionalOnly,
657 sizeof(kSamplePacketAdditionalOnly));
658
659 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
660 "hello._privet._tcp.local"));
661 }
662
TEST_F(MDnsTest,TransactionTimeout)663 TEST_F(MDnsTest, TransactionTimeout) {
664 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
665
666 scoped_ptr<MDnsTransaction> transaction_privet =
667 test_client_.CreateTransaction(
668 dns_protocol::kTypePTR, "_privet._tcp.local",
669 MDnsTransaction::QUERY_NETWORK |
670 MDnsTransaction::QUERY_CACHE |
671 MDnsTransaction::SINGLE_RESULT,
672 base::Bind(&MDnsTest::MockableRecordCallback,
673 base::Unretained(this)));
674
675 ASSERT_TRUE(transaction_privet->Start());
676
677 EXPECT_CALL(*this,
678 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
679 .Times(Exactly(1))
680 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
681
682 RunFor(base::TimeDelta::FromSeconds(4));
683 }
684
TEST_F(MDnsTest,TransactionMultipleRecords)685 TEST_F(MDnsTest, TransactionMultipleRecords) {
686 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
687
688 scoped_ptr<MDnsTransaction> transaction_privet =
689 test_client_.CreateTransaction(
690 dns_protocol::kTypePTR, "_privet._tcp.local",
691 MDnsTransaction::QUERY_NETWORK |
692 MDnsTransaction::QUERY_CACHE ,
693 base::Bind(&MDnsTest::MockableRecordCallback,
694 base::Unretained(this)));
695
696 ASSERT_TRUE(transaction_privet->Start());
697
698 PtrRecordCopyContainer record_privet;
699 PtrRecordCopyContainer record_privet2;
700
701 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
702 .Times(Exactly(2))
703 .WillOnce(Invoke(&record_privet,
704 &PtrRecordCopyContainer::SaveWithDummyArg))
705 .WillOnce(Invoke(&record_privet2,
706 &PtrRecordCopyContainer::SaveWithDummyArg));
707
708 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
709 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
710
711 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
712 "hello._privet._tcp.local"));
713
714 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
715 "zzzzz._privet._tcp.local"));
716
717 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
718 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
719
720 RunFor(base::TimeDelta::FromSeconds(4));
721 }
722
TEST_F(MDnsTest,TransactionReentrantDelete)723 TEST_F(MDnsTest, TransactionReentrantDelete) {
724 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
725
726 transaction_ = test_client_.CreateTransaction(
727 dns_protocol::kTypePTR, "_privet._tcp.local",
728 MDnsTransaction::QUERY_NETWORK |
729 MDnsTransaction::QUERY_CACHE |
730 MDnsTransaction::SINGLE_RESULT,
731 base::Bind(&MDnsTest::MockableRecordCallback,
732 base::Unretained(this)));
733
734 ASSERT_TRUE(transaction_->Start());
735
736 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
737 NULL))
738 .Times(Exactly(1))
739 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
740 InvokeWithoutArgs(this, &MDnsTest::Stop)));
741
742 RunFor(base::TimeDelta::FromSeconds(4));
743
744 EXPECT_EQ(NULL, transaction_.get());
745 }
746
TEST_F(MDnsTest,TransactionReentrantDeleteFromCache)747 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
748 StrictMock<MockListenerDelegate> delegate_irrelevant;
749 scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener(
750 dns_protocol::kTypeA, "codereview.chromium.local",
751 &delegate_irrelevant);
752 ASSERT_TRUE(listener_irrelevant->Start());
753
754 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
755
756 transaction_ = test_client_.CreateTransaction(
757 dns_protocol::kTypePTR, "_privet._tcp.local",
758 MDnsTransaction::QUERY_NETWORK |
759 MDnsTransaction::QUERY_CACHE,
760 base::Bind(&MDnsTest::MockableRecordCallback,
761 base::Unretained(this)));
762
763 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
764 .Times(Exactly(1))
765 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
766
767 ASSERT_TRUE(transaction_->Start());
768
769 EXPECT_EQ(NULL, transaction_.get());
770 }
771
TEST_F(MDnsTest,TransactionReentrantCacheLookupStart)772 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
773 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
774
775 scoped_ptr<MDnsTransaction> transaction1 =
776 test_client_.CreateTransaction(
777 dns_protocol::kTypePTR, "_privet._tcp.local",
778 MDnsTransaction::QUERY_NETWORK |
779 MDnsTransaction::QUERY_CACHE |
780 MDnsTransaction::SINGLE_RESULT,
781 base::Bind(&MDnsTest::MockableRecordCallback,
782 base::Unretained(this)));
783
784 scoped_ptr<MDnsTransaction> transaction2 =
785 test_client_.CreateTransaction(
786 dns_protocol::kTypePTR, "_printer._tcp.local",
787 MDnsTransaction::QUERY_CACHE |
788 MDnsTransaction::SINGLE_RESULT,
789 base::Bind(&MDnsTest::MockableRecordCallback2,
790 base::Unretained(this)));
791
792 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
793 _))
794 .Times(Exactly(1));
795
796 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
797 _))
798 .Times(Exactly(1))
799 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
800 &MDnsTransaction::Start)));
801
802 ASSERT_TRUE(transaction1->Start());
803
804 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
805 }
806
TEST_F(MDnsTest,GoodbyePacketNotification)807 TEST_F(MDnsTest, GoodbyePacketNotification) {
808 StrictMock<MockListenerDelegate> delegate_privet;
809
810 scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener(
811 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
812 ASSERT_TRUE(listener_privet->Start());
813
814 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
815
816 RunFor(base::TimeDelta::FromSeconds(2));
817 }
818
TEST_F(MDnsTest,GoodbyePacketRemoval)819 TEST_F(MDnsTest, GoodbyePacketRemoval) {
820 StrictMock<MockListenerDelegate> delegate_privet;
821
822 scoped_ptr<MDnsListener> listener_privet =
823 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
824 &delegate_privet);
825 ASSERT_TRUE(listener_privet->Start());
826
827 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
828 .Times(Exactly(1));
829
830 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
831
832 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
833
834 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
835 .Times(Exactly(1));
836
837 RunFor(base::TimeDelta::FromSeconds(2));
838 }
839
840 // In order to reliably test reentrant listener deletes, we create two listeners
841 // and have each of them delete both, so we're guaranteed to try and deliver a
842 // callback to at least one deleted listener.
843
TEST_F(MDnsTest,ListenerReentrantDelete)844 TEST_F(MDnsTest, ListenerReentrantDelete) {
845 StrictMock<MockListenerDelegate> delegate_privet;
846
847 listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR,
848 "_privet._tcp.local",
849 &delegate_privet);
850
851 listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR,
852 "_privet._tcp.local",
853 &delegate_privet);
854
855 ASSERT_TRUE(listener1_->Start());
856
857 ASSERT_TRUE(listener2_->Start());
858
859 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
860 .Times(Exactly(1))
861 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
862
863 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
864
865 EXPECT_EQ(NULL, listener1_.get());
866 EXPECT_EQ(NULL, listener2_.get());
867 }
868
ACTION_P(SaveIPAddress,ip_container)869 ACTION_P(SaveIPAddress, ip_container) {
870 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
871 ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>();
872
873 *ip_container = arg1->template rdata<ARecordRdata>()->address();
874 }
875
TEST_F(MDnsTest,DoubleRecordDisagreeing)876 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
877 IPAddressNumber address;
878 StrictMock<MockListenerDelegate> delegate_privet;
879
880 scoped_ptr<MDnsListener> listener_privet =
881 test_client_.CreateListener(dns_protocol::kTypeA, "privet.local",
882 &delegate_privet);
883
884 ASSERT_TRUE(listener_privet->Start());
885
886 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
887 .Times(Exactly(1))
888 .WillOnce(SaveIPAddress(&address));
889
890 SimulatePacketReceive(kCorruptedPacketDoubleRecord,
891 sizeof(kCorruptedPacketDoubleRecord));
892
893 EXPECT_EQ("2.3.4.5", IPAddressToString(address));
894 }
895
TEST_F(MDnsTest,NsecWithListener)896 TEST_F(MDnsTest, NsecWithListener) {
897 StrictMock<MockListenerDelegate> delegate_privet;
898 scoped_ptr<MDnsListener> listener_privet =
899 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
900 &delegate_privet);
901
902 // Test to make sure nsec callback is NOT called for PTR
903 // (which is marked as existing).
904 StrictMock<MockListenerDelegate> delegate_privet2;
905 scoped_ptr<MDnsListener> listener_privet2 =
906 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
907 &delegate_privet2);
908
909 ASSERT_TRUE(listener_privet->Start());
910
911 EXPECT_CALL(delegate_privet,
912 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
913
914 SimulatePacketReceive(kSamplePacketNsec,
915 sizeof(kSamplePacketNsec));
916 }
917
TEST_F(MDnsTest,NsecWithTransactionFromNetwork)918 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
919 scoped_ptr<MDnsTransaction> transaction_privet =
920 test_client_.CreateTransaction(
921 dns_protocol::kTypeA, "_privet._tcp.local",
922 MDnsTransaction::QUERY_NETWORK |
923 MDnsTransaction::QUERY_CACHE |
924 MDnsTransaction::SINGLE_RESULT,
925 base::Bind(&MDnsTest::MockableRecordCallback,
926 base::Unretained(this)));
927
928 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
929
930 ASSERT_TRUE(transaction_privet->Start());
931
932 EXPECT_CALL(*this,
933 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
934
935 SimulatePacketReceive(kSamplePacketNsec,
936 sizeof(kSamplePacketNsec));
937 }
938
TEST_F(MDnsTest,NsecWithTransactionFromCache)939 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
940 // Force mDNS to listen.
941 StrictMock<MockListenerDelegate> delegate_irrelevant;
942 scoped_ptr<MDnsListener> listener_irrelevant =
943 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
944 &delegate_irrelevant);
945 listener_irrelevant->Start();
946
947 SimulatePacketReceive(kSamplePacketNsec,
948 sizeof(kSamplePacketNsec));
949
950 EXPECT_CALL(*this,
951 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
952
953 scoped_ptr<MDnsTransaction> transaction_privet_a =
954 test_client_.CreateTransaction(
955 dns_protocol::kTypeA, "_privet._tcp.local",
956 MDnsTransaction::QUERY_NETWORK |
957 MDnsTransaction::QUERY_CACHE |
958 MDnsTransaction::SINGLE_RESULT,
959 base::Bind(&MDnsTest::MockableRecordCallback,
960 base::Unretained(this)));
961
962 ASSERT_TRUE(transaction_privet_a->Start());
963
964 // Test that a PTR transaction does NOT consider the same NSEC record to be a
965 // valid answer to the query
966
967 scoped_ptr<MDnsTransaction> transaction_privet_ptr =
968 test_client_.CreateTransaction(
969 dns_protocol::kTypePTR, "_privet._tcp.local",
970 MDnsTransaction::QUERY_NETWORK |
971 MDnsTransaction::QUERY_CACHE |
972 MDnsTransaction::SINGLE_RESULT,
973 base::Bind(&MDnsTest::MockableRecordCallback,
974 base::Unretained(this)));
975
976 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
977
978 ASSERT_TRUE(transaction_privet_ptr->Start());
979 }
980
TEST_F(MDnsTest,NsecConflictRemoval)981 TEST_F(MDnsTest, NsecConflictRemoval) {
982 StrictMock<MockListenerDelegate> delegate_privet;
983 scoped_ptr<MDnsListener> listener_privet =
984 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
985 &delegate_privet);
986
987 ASSERT_TRUE(listener_privet->Start());
988
989 const RecordParsed* record1;
990 const RecordParsed* record2;
991
992 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
993 .WillOnce(SaveArg<1>(&record1));
994
995 SimulatePacketReceive(kSamplePacketAPrivet,
996 sizeof(kSamplePacketAPrivet));
997
998 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
999 .WillOnce(SaveArg<1>(&record2));
1000
1001 EXPECT_CALL(delegate_privet,
1002 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1003
1004 SimulatePacketReceive(kSamplePacketNsec,
1005 sizeof(kSamplePacketNsec));
1006
1007 EXPECT_EQ(record1, record2);
1008 }
1009
1010
1011 // Note: These tests assume that the ipv4 socket will always be created first.
1012 // This is a simplifying assumption based on the way the code works now.
1013 class SimpleMockSocketFactory : public MDnsSocketFactory {
1014 public:
CreateSockets(ScopedVector<DatagramServerSocket> * sockets)1015 virtual void CreateSockets(
1016 ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1017 sockets->clear();
1018 sockets->swap(sockets_);
1019 }
1020
PushSocket(DatagramServerSocket * socket)1021 void PushSocket(DatagramServerSocket* socket) {
1022 sockets_.push_back(socket);
1023 }
1024
1025 private:
1026 ScopedVector<DatagramServerSocket> sockets_;
1027 };
1028
1029 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1030 public:
HandlePacket(DnsResponse * response,int size)1031 virtual void HandlePacket(DnsResponse* response, int size) {
1032 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1033 }
1034
1035 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1036
1037 MOCK_METHOD1(OnConnectionError, void(int error));
1038 };
1039
1040 class MDnsConnectionTest : public ::testing::Test {
1041 public:
MDnsConnectionTest()1042 MDnsConnectionTest() : connection_(&delegate_) {
1043 }
1044
1045 protected:
1046 // Follow successful connection initialization.
SetUp()1047 virtual void SetUp() OVERRIDE {
1048 socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4);
1049 socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6);
1050 factory_.PushSocket(socket_ipv6_);
1051 factory_.PushSocket(socket_ipv4_);
1052 }
1053
InitConnection()1054 bool InitConnection() {
1055 return connection_.Init(&factory_);
1056 }
1057
1058 StrictMock<MockMDnsConnectionDelegate> delegate_;
1059
1060 MockMDnsDatagramServerSocket* socket_ipv4_;
1061 MockMDnsDatagramServerSocket* socket_ipv6_;
1062 SimpleMockSocketFactory factory_;
1063 MDnsConnection connection_;
1064 TestCompletionCallback callback_;
1065 };
1066
TEST_F(MDnsConnectionTest,ReceiveSynchronous)1067 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1068 std::string sample_packet = MakeString(kSamplePacket1,
1069 sizeof(kSamplePacket1));
1070
1071 socket_ipv6_->SetResponsePacket(sample_packet);
1072 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1073 .WillOnce(Return(ERR_IO_PENDING));
1074 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1075 .WillOnce(
1076 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow))
1077 .WillOnce(Return(ERR_IO_PENDING));
1078
1079 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1080
1081 ASSERT_TRUE(InitConnection());
1082 }
1083
TEST_F(MDnsConnectionTest,ReceiveAsynchronous)1084 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1085 std::string sample_packet = MakeString(kSamplePacket1,
1086 sizeof(kSamplePacket1));
1087 socket_ipv6_->SetResponsePacket(sample_packet);
1088 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1089 .WillOnce(Return(ERR_IO_PENDING));
1090 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1091 .WillOnce(
1092 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1093 .WillOnce(Return(ERR_IO_PENDING));
1094
1095 ASSERT_TRUE(InitConnection());
1096
1097 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1098
1099 base::MessageLoop::current()->RunUntilIdle();
1100 }
1101
TEST_F(MDnsConnectionTest,Send)1102 TEST_F(MDnsConnectionTest, Send) {
1103 std::string sample_packet = MakeString(kSamplePacket1,
1104 sizeof(kSamplePacket1));
1105
1106 scoped_refptr<IOBufferWithSize> buf(
1107 new IOBufferWithSize(sizeof kSamplePacket1));
1108 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1109
1110 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1111 .WillOnce(Return(ERR_IO_PENDING));
1112 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1113 .WillOnce(Return(ERR_IO_PENDING));
1114
1115 ASSERT_TRUE(InitConnection());
1116
1117 EXPECT_CALL(*socket_ipv4_,
1118 SendToInternal(sample_packet, "224.0.0.251:5353", _));
1119 EXPECT_CALL(*socket_ipv6_,
1120 SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1121
1122 connection_.Send(buf, buf->size());
1123 }
1124
TEST_F(MDnsConnectionTest,Error)1125 TEST_F(MDnsConnectionTest, Error) {
1126 CompletionCallback callback;
1127
1128 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1129 .WillOnce(Return(ERR_IO_PENDING));
1130 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1131 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1132
1133 ASSERT_TRUE(InitConnection());
1134
1135 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1136 callback.Run(ERR_SOCKET_NOT_CONNECTED);
1137 }
1138
1139 } // namespace
1140
1141 } // namespace net
1142