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 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
267const 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
290const 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
313const 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
336std::string MakeString(const uint8* data, unsigned size) {
337  return std::string(reinterpret_cast<const char*>(data), size);
338}
339
340class 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
373class 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
403class 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
412void MDnsTest::SetUp() {
413  test_client_.StartListening(&socket_factory_);
414}
415
416void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
417  socket_factory_.SimulateReceive(packet, size);
418}
419
420void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
421  EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
422      .Times(2);
423}
424
425void MDnsTest::DeleteTransaction() {
426  transaction_.reset();
427}
428
429void MDnsTest::DeleteBothListeners() {
430  listener1_.reset();
431  listener2_.reset();
432}
433
434void 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
444void MDnsTest::Stop() {
445  base::MessageLoop::current()->Quit();
446}
447
448TEST_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
493TEST_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
529TEST_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
562TEST_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
589TEST_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
605TEST_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
639TEST_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
663TEST_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
685TEST_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
723TEST_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
747TEST_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
772TEST_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
807TEST_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
819TEST_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
844TEST_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
869ACTION_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
876TEST_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
896TEST_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
918TEST_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
939TEST_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
981TEST_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.
1013class SimpleMockSocketFactory : public MDnsSocketFactory {
1014 public:
1015  virtual void CreateSockets(
1016      ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1017    sockets->clear();
1018    sockets->swap(sockets_);
1019  }
1020
1021  void PushSocket(DatagramServerSocket* socket) {
1022    sockets_.push_back(socket);
1023  }
1024
1025 private:
1026  ScopedVector<DatagramServerSocket> sockets_;
1027};
1028
1029class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1030 public:
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
1040class MDnsConnectionTest : public ::testing::Test {
1041 public:
1042  MDnsConnectionTest() : connection_(&delegate_) {
1043  }
1044
1045 protected:
1046  // Follow successful connection initialization.
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
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
1067TEST_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
1084TEST_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
1102TEST_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
1125TEST_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