Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / dns / mdns_client_unittest.cc
blob0186839da04aa80fefd9ab11c7b389adadeed51d
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.
5 #include <queue>
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"
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::_;
27 namespace net {
29 namespace {
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
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,
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
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
74 // Question is corrupted and cannot be read.
75 0x99, 'h', 'e', 'l', 'l', 'o',
76 0x00,
77 0x00, 0x00,
78 0x00, 0x00,
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,
93 // Answer 2
94 0x08, '_', 'p', 'r', // Useless trailing data.
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
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,
119 // Answer 2
120 0x08, '_', 'p', 'r', // Useless trailing data.
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
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,
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,
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
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,
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
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
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,
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
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
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.
244 const uint8 kQueryPacketPrivetA[] = {
245 // Header
246 0x00, 0x00, // ID is zeroed out
247 0x00, 0x00, // No flags.
248 0x00, 0x01, // One question.
249 0x00, 0x00, // 0 RRs (answers)
250 0x00, 0x00, // 0 authority RRs
251 0x00, 0x00, // 0 additional RRs
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.
263 const uint8 kSamplePacketAdditionalOnly[] = {
264 // Header
265 0x00, 0x00, // ID is zeroed out
266 0x81, 0x80, // Standard query response, RA, no error
267 0x00, 0x00, // No questions (for simplicity)
268 0x00, 0x00, // 2 RRs (answers)
269 0x00, 0x00, // 0 authority RRs
270 0x00, 0x01, // 0 additional RRs
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,
286 const uint8 kSamplePacketNsec[] = {
287 // Header
288 0x00, 0x00, // ID is zeroed out
289 0x81, 0x80, // Standard query response, RA, no error
290 0x00, 0x00, // No questions (for simplicity)
291 0x00, 0x01, // 1 RR (answers)
292 0x00, 0x00, // 0 authority RRs
293 0x00, 0x00, // 0 additional RRs
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
309 const uint8 kSamplePacketAPrivet[] = {
310 // Header
311 0x00, 0x00, // ID is zeroed out
312 0x81, 0x80, // Standard query response, RA, no error
313 0x00, 0x00, // No questions (for simplicity)
314 0x00, 0x01, // 1 RR (answers)
315 0x00, 0x00, // 0 authority RRs
316 0x00, 0x00, // 0 additional RRs
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,
332 const uint8 kSamplePacketGoodbye[] = {
333 // Header
334 0x00, 0x00, // ID is zeroed out
335 0x81, 0x80, // Standard query response, RA, no error
336 0x00, 0x00, // No questions (for simplicity)
337 0x00, 0x01, // 2 RRs (answers)
338 0x00, 0x00, // 0 authority RRs
339 0x00, 0x00, // 0 additional RRs
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,
355 std::string MakeString(const uint8* data, unsigned size) {
356 return std::string(reinterpret_cast<const char*>(data), size);
359 class PtrRecordCopyContainer {
360 public:
361 PtrRecordCopyContainer() {}
362 ~PtrRecordCopyContainer() {}
364 bool is_set() const { return set_; }
366 void SaveWithDummyArg(int unused, const RecordParsed* value) {
367 Save(value);
370 void Save(const RecordParsed* value) {
371 set_ = true;
372 name_ = value->name();
373 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
374 ttl_ = value->ttl();
377 bool IsRecordWith(std::string name, std::string ptrdomain) {
378 return set_ && name_ == name && ptrdomain_ == ptrdomain;
381 const std::string& name() { return name_; }
382 const std::string& ptrdomain() { return ptrdomain_; }
383 int ttl() { return ttl_; }
385 private:
386 bool set_;
387 std::string name_;
388 std::string ptrdomain_;
389 int ttl_;
392 class MDnsTest : public ::testing::Test {
393 public:
394 virtual void SetUp() OVERRIDE;
395 void DeleteTransaction();
396 void DeleteBothListeners();
397 void RunFor(base::TimeDelta time_period);
398 void Stop();
400 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
401 const RecordParsed* record));
403 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
404 const RecordParsed* record));
407 protected:
408 void ExpectPacket(const uint8* packet, unsigned size);
409 void SimulatePacketReceive(const uint8* packet, unsigned size);
411 MDnsClientImpl test_client_;
412 IPEndPoint mdns_ipv4_endpoint_;
413 StrictMock<MockMDnsSocketFactory> socket_factory_;
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_;
422 class MockListenerDelegate : public MDnsListener::Delegate {
423 public:
424 MOCK_METHOD2(OnRecordUpdate,
425 void(MDnsListener::UpdateType update,
426 const RecordParsed* records));
427 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
428 MOCK_METHOD0(OnCachePurged, void());
431 void MDnsTest::SetUp() {
432 test_client_.StartListening(&socket_factory_);
435 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
436 socket_factory_.SimulateReceive(packet, size);
439 void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) {
440 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size)))
441 .Times(2);
444 void MDnsTest::DeleteTransaction() {
445 transaction_.reset();
448 void MDnsTest::DeleteBothListeners() {
449 listener1_.reset();
450 listener2_.reset();
453 void MDnsTest::RunFor(base::TimeDelta time_period) {
454 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
455 base::Unretained(this)));
456 base::MessageLoop::current()->PostDelayedTask(
457 FROM_HERE, callback.callback(), time_period);
459 base::MessageLoop::current()->Run();
460 callback.Cancel();
463 void MDnsTest::Stop() {
464 base::MessageLoop::current()->Quit();
467 TEST_F(MDnsTest, PassiveListeners) {
468 StrictMock<MockListenerDelegate> delegate_privet;
469 StrictMock<MockListenerDelegate> delegate_printer;
471 PtrRecordCopyContainer record_privet;
472 PtrRecordCopyContainer record_printer;
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);
481 ASSERT_TRUE(listener_privet->Start());
482 ASSERT_TRUE(listener_printer->Start());
484 // Send the same packet twice to ensure no records are double-counted.
486 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
487 .Times(Exactly(1))
488 .WillOnce(Invoke(
489 &record_privet,
490 &PtrRecordCopyContainer::SaveWithDummyArg));
492 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
493 .Times(Exactly(1))
494 .WillOnce(Invoke(
495 &record_printer,
496 &PtrRecordCopyContainer::SaveWithDummyArg));
499 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
500 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
502 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
503 "hello._privet._tcp.local"));
505 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
506 "hello._printer._tcp.local"));
508 listener_privet.reset();
509 listener_printer.reset();
512 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
513 StrictMock<MockListenerDelegate> delegate_privet;
515 PtrRecordCopyContainer record_privet;
516 PtrRecordCopyContainer record_privet2;
518 scoped_ptr<MDnsListener> listener_privet =
519 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
520 &delegate_privet);
522 ASSERT_TRUE(listener_privet->Start());
524 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
525 .Times(Exactly(1))
526 .WillOnce(Invoke(
527 &record_privet,
528 &PtrRecordCopyContainer::SaveWithDummyArg));
530 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
532 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
533 "hello._privet._tcp.local"));
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)));
542 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
544 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
545 "hello._privet._tcp.local"));
548 TEST_F(MDnsTest, MalformedPacket) {
549 StrictMock<MockListenerDelegate> delegate_printer;
551 PtrRecordCopyContainer record_printer;
553 scoped_ptr<MDnsListener> listener_printer =
554 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
555 &delegate_printer);
557 ASSERT_TRUE(listener_printer->Start());
559 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
560 .Times(Exactly(1))
561 .WillOnce(Invoke(
562 &record_printer,
563 &PtrRecordCopyContainer::SaveWithDummyArg));
565 // First, send unsalvagable packet to ensure we can deal with it.
566 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
567 sizeof(kCorruptedPacketUnsalvagable));
569 // Regression test: send a packet where the question cannot be read.
570 SimulatePacketReceive(kCorruptedPacketBadQuestion,
571 sizeof(kCorruptedPacketBadQuestion));
573 // Then send salvagable packet to ensure we can extract useful records.
574 SimulatePacketReceive(kCorruptedPacketSalvagable,
575 sizeof(kCorruptedPacketSalvagable));
577 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
578 "hello._printer._tcp.local"));
581 TEST_F(MDnsTest, TransactionWithEmptyCache) {
582 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
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)));
593 ASSERT_TRUE(transaction_privet->Start());
595 PtrRecordCopyContainer record_privet;
597 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
598 .Times(Exactly(1))
599 .WillOnce(Invoke(&record_privet,
600 &PtrRecordCopyContainer::SaveWithDummyArg));
602 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
604 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
605 "hello._privet._tcp.local"));
608 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
609 scoped_ptr<MDnsTransaction> transaction_privet =
610 test_client_.CreateTransaction(
611 dns_protocol::kTypePTR, "_privet._tcp.local",
612 MDnsTransaction::QUERY_CACHE |
613 MDnsTransaction::SINGLE_RESULT,
614 base::Bind(&MDnsTest::MockableRecordCallback,
615 base::Unretained(this)));
617 EXPECT_CALL(*this,
618 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
619 .Times(Exactly(1));
621 ASSERT_TRUE(transaction_privet->Start());
624 TEST_F(MDnsTest, TransactionWithCache) {
625 // Listener to force the client to listen
626 StrictMock<MockListenerDelegate> delegate_irrelevant;
627 scoped_ptr<MDnsListener> listener_irrelevant =
628 test_client_.CreateListener(dns_protocol::kTypeA,
629 "codereview.chromium.local",
630 &delegate_irrelevant);
632 ASSERT_TRUE(listener_irrelevant->Start());
634 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
637 PtrRecordCopyContainer record_privet;
639 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
640 .WillOnce(Invoke(&record_privet,
641 &PtrRecordCopyContainer::SaveWithDummyArg));
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)));
652 ASSERT_TRUE(transaction_privet->Start());
654 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
655 "hello._privet._tcp.local"));
658 TEST_F(MDnsTest, AdditionalRecords) {
659 StrictMock<MockListenerDelegate> delegate_privet;
661 PtrRecordCopyContainer record_privet;
663 scoped_ptr<MDnsListener> listener_privet =
664 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
665 &delegate_privet);
667 ASSERT_TRUE(listener_privet->Start());
669 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
670 .Times(Exactly(1))
671 .WillOnce(Invoke(
672 &record_privet,
673 &PtrRecordCopyContainer::SaveWithDummyArg));
675 SimulatePacketReceive(kSamplePacketAdditionalOnly,
676 sizeof(kSamplePacketAdditionalOnly));
678 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
679 "hello._privet._tcp.local"));
682 TEST_F(MDnsTest, TransactionTimeout) {
683 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
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)));
694 ASSERT_TRUE(transaction_privet->Start());
696 EXPECT_CALL(*this,
697 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
698 .Times(Exactly(1))
699 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
701 RunFor(base::TimeDelta::FromSeconds(4));
704 TEST_F(MDnsTest, TransactionMultipleRecords) {
705 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
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)));
715 ASSERT_TRUE(transaction_privet->Start());
717 PtrRecordCopyContainer record_privet;
718 PtrRecordCopyContainer record_privet2;
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));
727 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
728 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
730 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
731 "hello._privet._tcp.local"));
733 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
734 "zzzzz._privet._tcp.local"));
736 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
737 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
739 RunFor(base::TimeDelta::FromSeconds(4));
742 TEST_F(MDnsTest, TransactionReentrantDelete) {
743 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
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)));
753 ASSERT_TRUE(transaction_->Start());
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)));
761 RunFor(base::TimeDelta::FromSeconds(4));
763 EXPECT_EQ(NULL, transaction_.get());
766 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
767 StrictMock<MockListenerDelegate> delegate_irrelevant;
768 scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener(
769 dns_protocol::kTypeA, "codereview.chromium.local",
770 &delegate_irrelevant);
771 ASSERT_TRUE(listener_irrelevant->Start());
773 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
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)));
782 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
783 .Times(Exactly(1))
784 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
786 ASSERT_TRUE(transaction_->Start());
788 EXPECT_EQ(NULL, transaction_.get());
791 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
792 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
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)));
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)));
811 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
813 .Times(Exactly(1));
815 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
817 .Times(Exactly(1))
818 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(),
819 &MDnsTransaction::Start)));
821 ASSERT_TRUE(transaction1->Start());
823 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
826 TEST_F(MDnsTest, GoodbyePacketNotification) {
827 StrictMock<MockListenerDelegate> delegate_privet;
829 scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener(
830 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
831 ASSERT_TRUE(listener_privet->Start());
833 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
835 RunFor(base::TimeDelta::FromSeconds(2));
838 TEST_F(MDnsTest, GoodbyePacketRemoval) {
839 StrictMock<MockListenerDelegate> delegate_privet;
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());
846 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
847 .Times(Exactly(1));
849 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
851 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
853 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
854 .Times(Exactly(1));
856 RunFor(base::TimeDelta::FromSeconds(2));
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.
863 TEST_F(MDnsTest, ListenerReentrantDelete) {
864 StrictMock<MockListenerDelegate> delegate_privet;
866 listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR,
867 "_privet._tcp.local",
868 &delegate_privet);
870 listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR,
871 "_privet._tcp.local",
872 &delegate_privet);
874 ASSERT_TRUE(listener1_->Start());
876 ASSERT_TRUE(listener2_->Start());
878 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
879 .Times(Exactly(1))
880 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
882 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
884 EXPECT_EQ(NULL, listener1_.get());
885 EXPECT_EQ(NULL, listener2_.get());
888 ACTION_P(SaveIPAddress, ip_container) {
889 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>();
890 ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>();
892 *ip_container = arg1->template rdata<ARecordRdata>()->address();
895 TEST_F(MDnsTest, DoubleRecordDisagreeing) {
896 IPAddressNumber address;
897 StrictMock<MockListenerDelegate> delegate_privet;
899 scoped_ptr<MDnsListener> listener_privet =
900 test_client_.CreateListener(dns_protocol::kTypeA, "privet.local",
901 &delegate_privet);
903 ASSERT_TRUE(listener_privet->Start());
905 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
906 .Times(Exactly(1))
907 .WillOnce(SaveIPAddress(&address));
909 SimulatePacketReceive(kCorruptedPacketDoubleRecord,
910 sizeof(kCorruptedPacketDoubleRecord));
912 EXPECT_EQ("2.3.4.5", IPAddressToString(address));
915 TEST_F(MDnsTest, NsecWithListener) {
916 StrictMock<MockListenerDelegate> delegate_privet;
917 scoped_ptr<MDnsListener> listener_privet =
918 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
919 &delegate_privet);
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);
928 ASSERT_TRUE(listener_privet->Start());
930 EXPECT_CALL(delegate_privet,
931 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
933 SimulatePacketReceive(kSamplePacketNsec,
934 sizeof(kSamplePacketNsec));
937 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
938 scoped_ptr<MDnsTransaction> transaction_privet =
939 test_client_.CreateTransaction(
940 dns_protocol::kTypeA, "_privet._tcp.local",
941 MDnsTransaction::QUERY_NETWORK |
942 MDnsTransaction::QUERY_CACHE |
943 MDnsTransaction::SINGLE_RESULT,
944 base::Bind(&MDnsTest::MockableRecordCallback,
945 base::Unretained(this)));
947 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
949 ASSERT_TRUE(transaction_privet->Start());
951 EXPECT_CALL(*this,
952 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
954 SimulatePacketReceive(kSamplePacketNsec,
955 sizeof(kSamplePacketNsec));
958 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
959 // Force mDNS to listen.
960 StrictMock<MockListenerDelegate> delegate_irrelevant;
961 scoped_ptr<MDnsListener> listener_irrelevant =
962 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
963 &delegate_irrelevant);
964 listener_irrelevant->Start();
966 SimulatePacketReceive(kSamplePacketNsec,
967 sizeof(kSamplePacketNsec));
969 EXPECT_CALL(*this,
970 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
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)));
981 ASSERT_TRUE(transaction_privet_a->Start());
983 // Test that a PTR transaction does NOT consider the same NSEC record to be a
984 // valid answer to the query
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)));
995 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2);
997 ASSERT_TRUE(transaction_privet_ptr->Start());
1000 TEST_F(MDnsTest, NsecConflictRemoval) {
1001 StrictMock<MockListenerDelegate> delegate_privet;
1002 scoped_ptr<MDnsListener> listener_privet =
1003 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
1004 &delegate_privet);
1006 ASSERT_TRUE(listener_privet->Start());
1008 const RecordParsed* record1;
1009 const RecordParsed* record2;
1011 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
1012 .WillOnce(SaveArg<1>(&record1));
1014 SimulatePacketReceive(kSamplePacketAPrivet,
1015 sizeof(kSamplePacketAPrivet));
1017 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
1018 .WillOnce(SaveArg<1>(&record2));
1020 EXPECT_CALL(delegate_privet,
1021 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA));
1023 SimulatePacketReceive(kSamplePacketNsec,
1024 sizeof(kSamplePacketNsec));
1026 EXPECT_EQ(record1, record2);
1030 TEST_F(MDnsTest, RefreshQuery) {
1031 StrictMock<MockListenerDelegate> delegate_privet;
1032 scoped_ptr<MDnsListener> listener_privet =
1033 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
1034 &delegate_privet);
1036 listener_privet->SetActiveRefresh(true);
1037 ASSERT_TRUE(listener_privet->Start());
1039 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _));
1041 SimulatePacketReceive(kSamplePacketAPrivet,
1042 sizeof(kSamplePacketAPrivet));
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);
1050 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _));
1052 RunFor(base::TimeDelta::FromSeconds(6));
1055 // Note: These tests assume that the ipv4 socket will always be created first.
1056 // This is a simplifying assumption based on the way the code works now.
1057 class SimpleMockSocketFactory : public MDnsSocketFactory {
1058 public:
1059 virtual void CreateSockets(
1060 ScopedVector<DatagramServerSocket>* sockets) OVERRIDE {
1061 sockets->clear();
1062 sockets->swap(sockets_);
1065 void PushSocket(DatagramServerSocket* socket) {
1066 sockets_.push_back(socket);
1069 private:
1070 ScopedVector<DatagramServerSocket> sockets_;
1073 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1074 public:
1075 virtual void HandlePacket(DnsResponse* response, int size) {
1076 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
1079 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
1081 MOCK_METHOD1(OnConnectionError, void(int error));
1084 class MDnsConnectionTest : public ::testing::Test {
1085 public:
1086 MDnsConnectionTest() : connection_(&delegate_) {
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_);
1098 bool InitConnection() {
1099 return connection_.Init(&factory_);
1102 StrictMock<MockMDnsConnectionDelegate> delegate_;
1104 MockMDnsDatagramServerSocket* socket_ipv4_;
1105 MockMDnsDatagramServerSocket* socket_ipv6_;
1106 SimpleMockSocketFactory factory_;
1107 MDnsConnection connection_;
1108 TestCompletionCallback callback_;
1111 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
1112 std::string sample_packet = MakeString(kSamplePacket1,
1113 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::HandleRecvNow))
1121 .WillOnce(Return(ERR_IO_PENDING));
1123 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1125 ASSERT_TRUE(InitConnection());
1128 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1129 std::string sample_packet = MakeString(kSamplePacket1,
1130 sizeof(kSamplePacket1));
1131 socket_ipv6_->SetResponsePacket(sample_packet);
1132 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1133 .WillOnce(Return(ERR_IO_PENDING));
1134 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1135 .WillOnce(
1136 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater))
1137 .WillOnce(Return(ERR_IO_PENDING));
1139 ASSERT_TRUE(InitConnection());
1141 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1143 base::MessageLoop::current()->RunUntilIdle();
1146 TEST_F(MDnsConnectionTest, Send) {
1147 std::string sample_packet = MakeString(kSamplePacket1,
1148 sizeof(kSamplePacket1));
1150 scoped_refptr<IOBufferWithSize> buf(
1151 new IOBufferWithSize(sizeof kSamplePacket1));
1152 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1154 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1155 .WillOnce(Return(ERR_IO_PENDING));
1156 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1157 .WillOnce(Return(ERR_IO_PENDING));
1159 ASSERT_TRUE(InitConnection());
1161 EXPECT_CALL(*socket_ipv4_,
1162 SendToInternal(sample_packet, "224.0.0.251:5353", _));
1163 EXPECT_CALL(*socket_ipv6_,
1164 SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1166 connection_.Send(buf, buf->size());
1169 TEST_F(MDnsConnectionTest, Error) {
1170 CompletionCallback callback;
1172 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1173 .WillOnce(Return(ERR_IO_PENDING));
1174 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1175 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1177 ASSERT_TRUE(InitConnection());
1179 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1180 callback.Run(ERR_SOCKET_NOT_CONNECTED);
1183 } // namespace
1185 } // namespace net