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
18using ::testing::Invoke;
19using ::testing::InvokeWithoutArgs;
20using ::testing::StrictMock;
21using ::testing::NiceMock;
22using ::testing::Exactly;
23using ::testing::Return;
24using ::testing::SaveArg;
25using ::testing::_;
26
27namespace net {
28
29namespace {
30
31const 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
65const 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
97const 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
123const 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
157const 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
191const 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
225const 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
244const 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
263const 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
286const 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
309const 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
332const 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
355std::string MakeString(const uint8* data, unsigned size) {
356  return std::string(reinterpret_cast<const char*>(data), size);
357}
358
359class 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
392class 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
422class 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
431void MDnsTest::SetUp() {
432  test_client_.StartListening(&socket_factory_);
433}
434
435void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
436  socket_factory_.SimulateReceive(packet, size);
437}
438
439void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
440  EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
441      .Times(2);
442}
443
444void MDnsTest::DeleteTransaction() {
445  transaction_.reset();
446}
447
448void MDnsTest::DeleteBothListeners() {
449  listener1_.reset();
450  listener2_.reset();
451}
452
453void 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
463void MDnsTest::Stop() {
464  base::MessageLoop::current()->Quit();
465}
466
467TEST_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
512TEST_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
548TEST_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
581TEST_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
608TEST_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
624TEST_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
658TEST_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
682TEST_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
704TEST_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
742TEST_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
766TEST_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
791TEST_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
826TEST_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
838TEST_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
863TEST_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
888ACTION_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
895TEST_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
915TEST_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
937TEST_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
958TEST_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
1000TEST_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
1030TEST_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.
1057class SimpleMockSocketFactory : public MDnsSocketFactory {
1058 public:
1059  virtual void CreateSockets(
1060      ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1061    sockets->clear();
1062    sockets->swap(sockets_);
1063  }
1064
1065  void PushSocket(DatagramServerSocket* socket) {
1066    sockets_.push_back(socket);
1067  }
1068
1069 private:
1070  ScopedVector<DatagramServerSocket> sockets_;
1071};
1072
1073class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1074 public:
1075  virtual void HandlePacket(DnsResponse* response, int size) {
1076    HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1077  }
1078
1079  MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1080
1081  MOCK_METHOD1(OnConnectionError, void(int error));
1082};
1083
1084class MDnsConnectionTest : public ::testing::Test {
1085 public:
1086  MDnsConnectionTest() : connection_(&delegate_) {
1087  }
1088
1089 protected:
1090  // Follow successful connection initialization.
1091  virtual void SetUp() OVERRIDE {
1092    socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4);
1093    socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6);
1094    factory_.PushSocket(socket_ipv6_);
1095    factory_.PushSocket(socket_ipv4_);
1096    sample_packet_ = MakeString(kSamplePacket1, sizeof(kSamplePacket1));
1097    sample_buffer_ = new StringIOBuffer(sample_packet_);
1098  }
1099
1100  bool InitConnection() {
1101    return connection_.Init(&factory_);
1102  }
1103
1104  StrictMock<MockMDnsConnectionDelegate> delegate_;
1105
1106  MockMDnsDatagramServerSocket* socket_ipv4_;
1107  MockMDnsDatagramServerSocket* socket_ipv6_;
1108  SimpleMockSocketFactory factory_;
1109  MDnsConnection connection_;
1110  TestCompletionCallback callback_;
1111  std::string sample_packet_;
1112  scoped_refptr<IOBuffer> sample_buffer_;
1113};
1114
1115TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1116  socket_ipv6_->SetResponsePacket(sample_packet_);
1117  EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1118      .WillOnce(Return(ERR_IO_PENDING));
1119  EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1120      .WillOnce(
1121          Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow))
1122      .WillOnce(Return(ERR_IO_PENDING));
1123
1124  EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1125  ASSERT_TRUE(InitConnection());
1126}
1127
1128TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1129  socket_ipv6_->SetResponsePacket(sample_packet_);
1130
1131  EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1132      .WillOnce(Return(ERR_IO_PENDING));
1133  EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1134      .Times(2)
1135      .WillOnce(
1136           Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1137      .WillOnce(Return(ERR_IO_PENDING));
1138
1139  ASSERT_TRUE(InitConnection());
1140
1141  EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet_));
1142
1143  base::MessageLoop::current()->RunUntilIdle();
1144}
1145
1146TEST_F(MDnsConnectionTest, Error) {
1147  CompletionCallback callback;
1148
1149  EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1150      .WillOnce(Return(ERR_IO_PENDING));
1151  EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1152      .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1153
1154  ASSERT_TRUE(InitConnection());
1155
1156  EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1157  callback.Run(ERR_SOCKET_NOT_CONNECTED);
1158  base::MessageLoop::current()->RunUntilIdle();
1159}
1160
1161class MDnsConnectionSendTest : public MDnsConnectionTest {
1162 protected:
1163  virtual void SetUp() OVERRIDE {
1164    MDnsConnectionTest::SetUp();
1165    EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1166        .WillOnce(Return(ERR_IO_PENDING));
1167    EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1168        .WillOnce(Return(ERR_IO_PENDING));
1169    EXPECT_TRUE(InitConnection());
1170  }
1171};
1172
1173TEST_F(MDnsConnectionSendTest, Send) {
1174  EXPECT_CALL(*socket_ipv4_,
1175              SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1176  EXPECT_CALL(*socket_ipv6_,
1177              SendToInternal(sample_packet_, "[ff02::fb]:5353", _));
1178
1179  connection_.Send(sample_buffer_, sample_packet_.size());
1180}
1181
1182TEST_F(MDnsConnectionSendTest, SendError) {
1183  CompletionCallback callback;
1184
1185  EXPECT_CALL(*socket_ipv4_,
1186              SendToInternal(sample_packet_, "224.0.0.251:5353", _));
1187  EXPECT_CALL(*socket_ipv6_,
1188              SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1189      .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_SOCKET_NOT_CONNECTED)));
1190
1191  connection_.Send(sample_buffer_, sample_packet_.size());
1192  EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1193  base::MessageLoop::current()->RunUntilIdle();
1194}
1195
1196TEST_F(MDnsConnectionSendTest, SendQueued) {
1197  // Send data immediately.
1198  EXPECT_CALL(*socket_ipv4_,
1199              SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1200      .Times(2)
1201      .WillRepeatedly(Return(OK));
1202
1203  CompletionCallback callback;
1204  // Delay sending data. Only the first call should be made.
1205  EXPECT_CALL(*socket_ipv6_,
1206              SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1207      .WillOnce(DoAll(SaveArg<2>(&callback), Return(ERR_IO_PENDING)));
1208
1209  connection_.Send(sample_buffer_, sample_packet_.size());
1210  connection_.Send(sample_buffer_, sample_packet_.size());
1211
1212  // The second IPv6 packed is not sent yet.
1213  EXPECT_CALL(*socket_ipv4_,
1214              SendToInternal(sample_packet_, "224.0.0.251:5353", _))
1215      .Times(0);
1216  // Expect call for the second IPv6 packed.
1217  EXPECT_CALL(*socket_ipv6_,
1218              SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1219      .WillOnce(Return(OK));
1220  callback.Run(OK);
1221}
1222
1223}  // namespace
1224
1225}  // namespace net
1226