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