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.
7 #include "base/location.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/time/clock.h"
13 #include "base/time/default_clock.h"
14 #include "base/timer/mock_timer.h"
15 #include "net/base/rand_callback.h"
16 #include "net/base/test_completion_callback.h"
17 #include "net/dns/mdns_client_impl.h"
18 #include "net/dns/mock_mdns_socket_factory.h"
19 #include "net/dns/record_rdata.h"
20 #include "net/udp/udp_client_socket.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using ::testing::Invoke
;
25 using ::testing::InvokeWithoutArgs
;
26 using ::testing::StrictMock
;
27 using ::testing::NiceMock
;
28 using ::testing::Exactly
;
29 using ::testing::Return
;
30 using ::testing::SaveArg
;
37 const uint8 kSamplePacket1
[] = {
39 0x00, 0x00, // ID is zeroed out
40 0x81, 0x80, // Standard query response, RA, no error
41 0x00, 0x00, // No questions (for simplicity)
42 0x00, 0x02, // 2 RRs (answers)
43 0x00, 0x00, // 0 authority RRs
44 0x00, 0x00, // 0 additional RRs
47 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
48 0x04, '_', 't', 'c', 'p',
49 0x05, 'l', 'o', 'c', 'a', 'l',
51 0x00, 0x0c, // TYPE is PTR.
52 0x00, 0x01, // CLASS is IN.
53 0x00, 0x00, // TTL (4 bytes) is 1 second;
55 0x00, 0x08, // RDLENGTH is 8 bytes.
56 0x05, 'h', 'e', 'l', 'l', 'o',
60 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
61 0xc0, 0x14, // Pointer to "._tcp.local"
62 0x00, 0x0c, // TYPE is PTR.
63 0x00, 0x01, // CLASS is IN.
64 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
66 0x00, 0x08, // RDLENGTH is 8 bytes.
67 0x05, 'h', 'e', 'l', 'l', 'o',
71 const uint8 kCorruptedPacketBadQuestion
[] = {
73 0x00, 0x00, // ID is zeroed out
74 0x81, 0x80, // Standard query response, RA, no error
75 0x00, 0x01, // One question
76 0x00, 0x02, // 2 RRs (answers)
77 0x00, 0x00, // 0 authority RRs
78 0x00, 0x00, // 0 additional RRs
80 // Question is corrupted and cannot be read.
81 0x99, 'h', 'e', 'l', 'l', 'o',
87 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
88 0x04, '_', 't', 'c', 'p',
89 0x05, 'l', 'o', 'c', 'a', 'l',
91 0x00, 0x0c, // TYPE is PTR.
92 0x00, 0x01, // CLASS is IN.
93 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
95 0x00, 0x99, // RDLENGTH is impossible
96 0x05, 'h', 'e', 'l', 'l', 'o',
100 0x08, '_', 'p', 'r', // Useless trailing data.
103 const uint8 kCorruptedPacketUnsalvagable
[] = {
105 0x00, 0x00, // ID is zeroed out
106 0x81, 0x80, // Standard query response, RA, no error
107 0x00, 0x00, // No questions (for simplicity)
108 0x00, 0x02, // 2 RRs (answers)
109 0x00, 0x00, // 0 authority RRs
110 0x00, 0x00, // 0 additional RRs
113 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
114 0x04, '_', 't', 'c', 'p',
115 0x05, 'l', 'o', 'c', 'a', 'l',
117 0x00, 0x0c, // TYPE is PTR.
118 0x00, 0x01, // CLASS is IN.
119 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
121 0x00, 0x99, // RDLENGTH is impossible
122 0x05, 'h', 'e', 'l', 'l', 'o',
126 0x08, '_', 'p', 'r', // Useless trailing data.
129 const uint8 kCorruptedPacketDoubleRecord
[] = {
131 0x00, 0x00, // ID is zeroed out
132 0x81, 0x80, // Standard query response, RA, no error
133 0x00, 0x00, // No questions (for simplicity)
134 0x00, 0x02, // 2 RRs (answers)
135 0x00, 0x00, // 0 authority RRs
136 0x00, 0x00, // 0 additional RRs
139 0x06, 'p', 'r', 'i', 'v', 'e', 't',
140 0x05, 'l', 'o', 'c', 'a', 'l',
142 0x00, 0x01, // TYPE is A.
143 0x00, 0x01, // CLASS is IN.
144 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
146 0x00, 0x04, // RDLENGTH is 4
150 // Answer 2 -- Same key
151 0x06, 'p', 'r', 'i', 'v', 'e', 't',
152 0x05, 'l', 'o', 'c', 'a', 'l',
154 0x00, 0x01, // TYPE is A.
155 0x00, 0x01, // CLASS is IN.
156 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
158 0x00, 0x04, // RDLENGTH is 4
163 const uint8 kCorruptedPacketSalvagable
[] = {
165 0x00, 0x00, // ID is zeroed out
166 0x81, 0x80, // Standard query response, RA, no error
167 0x00, 0x00, // No questions (for simplicity)
168 0x00, 0x02, // 2 RRs (answers)
169 0x00, 0x00, // 0 authority RRs
170 0x00, 0x00, // 0 additional RRs
173 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
174 0x04, '_', 't', 'c', 'p',
175 0x05, 'l', 'o', 'c', 'a', 'l',
177 0x00, 0x0c, // TYPE is PTR.
178 0x00, 0x01, // CLASS is IN.
179 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
181 0x00, 0x08, // RDLENGTH is 8 bytes.
182 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
186 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
187 0xc0, 0x14, // Pointer to "._tcp.local"
188 0x00, 0x0c, // TYPE is PTR.
189 0x00, 0x01, // CLASS is IN.
190 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
192 0x00, 0x08, // RDLENGTH is 8 bytes.
193 0x05, 'h', 'e', 'l', 'l', 'o',
197 const uint8 kSamplePacket2
[] = {
199 0x00, 0x00, // ID is zeroed out
200 0x81, 0x80, // Standard query response, RA, no error
201 0x00, 0x00, // No questions (for simplicity)
202 0x00, 0x02, // 2 RRs (answers)
203 0x00, 0x00, // 0 authority RRs
204 0x00, 0x00, // 0 additional RRs
207 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
208 0x04, '_', 't', 'c', 'p',
209 0x05, 'l', 'o', 'c', 'a', 'l',
211 0x00, 0x0c, // TYPE is PTR.
212 0x00, 0x01, // CLASS is IN.
213 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
215 0x00, 0x08, // RDLENGTH is 8 bytes.
216 0x05, 'z', 'z', 'z', 'z', 'z',
220 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
221 0xc0, 0x14, // Pointer to "._tcp.local"
222 0x00, 0x0c, // TYPE is PTR.
223 0x00, 0x01, // CLASS is IN.
224 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
226 0x00, 0x08, // RDLENGTH is 8 bytes.
227 0x05, 'z', 'z', 'z', 'z', 'z',
231 const uint8 kSamplePacket3
[] = {
233 0x00, 0x00, // ID is zeroed out
234 0x81, 0x80, // Standard query response, RA, no error
235 0x00, 0x00, // No questions (for simplicity)
236 0x00, 0x02, // 2 RRs (answers)
237 0x00, 0x00, // 0 authority RRs
238 0x00, 0x00, // 0 additional RRs
241 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', //
242 0x04, '_', 't', 'c', 'p', //
243 0x05, 'l', 'o', 'c', 'a', 'l', //
244 0x00, 0x00, 0x0c, // TYPE is PTR.
245 0x00, 0x01, // CLASS is IN.
246 0x00, 0x00, // TTL (4 bytes) is 1 second;
248 0x00, 0x08, // RDLENGTH is 8 bytes.
249 0x05, 'h', 'e', 'l', 'l', 'o', //
253 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', //
254 0xc0, 0x14, // Pointer to "._tcp.local"
255 0x00, 0x0c, // TYPE is PTR.
256 0x00, 0x01, // CLASS is IN.
257 0x00, 0x00, // TTL (4 bytes) is 3 seconds.
259 0x00, 0x08, // RDLENGTH is 8 bytes.
260 0x05, 'h', 'e', 'l', 'l', 'o', //
263 const uint8 kQueryPacketPrivet
[] = {
265 0x00, 0x00, // ID is zeroed out
266 0x00, 0x00, // No flags.
267 0x00, 0x01, // One question.
268 0x00, 0x00, // 0 RRs (answers)
269 0x00, 0x00, // 0 authority RRs
270 0x00, 0x00, // 0 additional RRs
273 // This part is echoed back from the respective query.
274 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
275 0x04, '_', 't', 'c', 'p',
276 0x05, 'l', 'o', 'c', 'a', 'l',
278 0x00, 0x0c, // TYPE is PTR.
279 0x00, 0x01, // CLASS is IN.
282 const uint8 kQueryPacketPrivetA
[] = {
284 0x00, 0x00, // ID is zeroed out
285 0x00, 0x00, // No flags.
286 0x00, 0x01, // One question.
287 0x00, 0x00, // 0 RRs (answers)
288 0x00, 0x00, // 0 authority RRs
289 0x00, 0x00, // 0 additional RRs
292 // This part is echoed back from the respective query.
293 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
294 0x04, '_', 't', 'c', 'p',
295 0x05, 'l', 'o', 'c', 'a', 'l',
297 0x00, 0x01, // TYPE is A.
298 0x00, 0x01, // CLASS is IN.
301 const uint8 kSamplePacketAdditionalOnly
[] = {
303 0x00, 0x00, // ID is zeroed out
304 0x81, 0x80, // Standard query response, RA, no error
305 0x00, 0x00, // No questions (for simplicity)
306 0x00, 0x00, // 2 RRs (answers)
307 0x00, 0x00, // 0 authority RRs
308 0x00, 0x01, // 0 additional RRs
311 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
312 0x04, '_', 't', 'c', 'p',
313 0x05, 'l', 'o', 'c', 'a', 'l',
315 0x00, 0x0c, // TYPE is PTR.
316 0x00, 0x01, // CLASS is IN.
317 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
319 0x00, 0x08, // RDLENGTH is 8 bytes.
320 0x05, 'h', 'e', 'l', 'l', 'o',
324 const uint8 kSamplePacketNsec
[] = {
326 0x00, 0x00, // ID is zeroed out
327 0x81, 0x80, // Standard query response, RA, no error
328 0x00, 0x00, // No questions (for simplicity)
329 0x00, 0x01, // 1 RR (answers)
330 0x00, 0x00, // 0 authority RRs
331 0x00, 0x00, // 0 additional RRs
334 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
335 0x04, '_', 't', 'c', 'p',
336 0x05, 'l', 'o', 'c', 'a', 'l',
338 0x00, 0x2f, // TYPE is NSEC.
339 0x00, 0x01, // CLASS is IN.
340 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
342 0x00, 0x06, // RDLENGTH is 6 bytes.
344 0x00, 0x02, 0x00, 0x08 // Only A record present
347 const uint8 kSamplePacketAPrivet
[] = {
349 0x00, 0x00, // ID is zeroed out
350 0x81, 0x80, // Standard query response, RA, no error
351 0x00, 0x00, // No questions (for simplicity)
352 0x00, 0x01, // 1 RR (answers)
353 0x00, 0x00, // 0 authority RRs
354 0x00, 0x00, // 0 additional RRs
357 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
358 0x04, '_', 't', 'c', 'p',
359 0x05, 'l', 'o', 'c', 'a', 'l',
361 0x00, 0x01, // TYPE is A.
362 0x00, 0x01, // CLASS is IN.
363 0x00, 0x00, // TTL (4 bytes) is 5 seconds
365 0x00, 0x04, // RDLENGTH is 4 bytes.
370 const uint8 kSamplePacketGoodbye
[] = {
372 0x00, 0x00, // ID is zeroed out
373 0x81, 0x80, // Standard query response, RA, no error
374 0x00, 0x00, // No questions (for simplicity)
375 0x00, 0x01, // 2 RRs (answers)
376 0x00, 0x00, // 0 authority RRs
377 0x00, 0x00, // 0 additional RRs
380 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
381 0x04, '_', 't', 'c', 'p',
382 0x05, 'l', 'o', 'c', 'a', 'l',
384 0x00, 0x0c, // TYPE is PTR.
385 0x00, 0x01, // CLASS is IN.
386 0x00, 0x00, // TTL (4 bytes) is zero;
388 0x00, 0x08, // RDLENGTH is 8 bytes.
389 0x05, 'z', 'z', 'z', 'z', 'z',
393 std::string
MakeString(const uint8
* data
, unsigned size
) {
394 return std::string(reinterpret_cast<const char*>(data
), size
);
397 class PtrRecordCopyContainer
{
399 PtrRecordCopyContainer() {}
400 ~PtrRecordCopyContainer() {}
402 bool is_set() const { return set_
; }
404 void SaveWithDummyArg(int unused
, const RecordParsed
* value
) {
408 void Save(const RecordParsed
* value
) {
410 name_
= value
->name();
411 ptrdomain_
= value
->rdata
<PtrRecordRdata
>()->ptrdomain();
415 bool IsRecordWith(std::string name
, std::string ptrdomain
) {
416 return set_
&& name_
== name
&& ptrdomain_
== ptrdomain
;
419 const std::string
& name() { return name_
; }
420 const std::string
& ptrdomain() { return ptrdomain_
; }
421 int ttl() { return ttl_
; }
426 std::string ptrdomain_
;
430 class MockClock
: public base::DefaultClock
{
432 MockClock() : base::DefaultClock() {}
433 virtual ~MockClock() {}
435 MOCK_METHOD0(Now
, base::Time());
438 DISALLOW_COPY_AND_ASSIGN(MockClock
);
441 class MockTimer
: public base::MockTimer
{
443 MockTimer() : base::MockTimer(false, false) {}
446 void Start(const tracked_objects::Location
& posted_from
,
447 base::TimeDelta delay
,
448 const base::Closure
& user_task
) {
449 StartObserver(posted_from
, delay
, user_task
);
450 base::MockTimer::Start(posted_from
, delay
, user_task
);
453 // StartObserver is invoked when MockTimer::Start() is called.
454 // Does not replace the behavior of MockTimer::Start().
455 MOCK_METHOD3(StartObserver
,
456 void(const tracked_objects::Location
& posted_from
,
457 base::TimeDelta delay
,
458 const base::Closure
& user_task
));
461 DISALLOW_COPY_AND_ASSIGN(MockTimer
);
466 class MDnsTest
: public ::testing::Test
{
468 void SetUp() override
;
469 void DeleteTransaction();
470 void DeleteBothListeners();
471 void RunFor(base::TimeDelta time_period
);
474 MOCK_METHOD2(MockableRecordCallback
, void(MDnsTransaction::Result result
,
475 const RecordParsed
* record
));
477 MOCK_METHOD2(MockableRecordCallback2
, void(MDnsTransaction::Result result
,
478 const RecordParsed
* record
));
481 void ExpectPacket(const uint8
* packet
, unsigned size
);
482 void SimulatePacketReceive(const uint8
* packet
, unsigned size
);
484 scoped_ptr
<MDnsClientImpl
> test_client_
;
485 IPEndPoint mdns_ipv4_endpoint_
;
486 StrictMock
<MockMDnsSocketFactory
> socket_factory_
;
488 // Transactions and listeners that can be deleted by class methods for
490 scoped_ptr
<MDnsTransaction
> transaction_
;
491 scoped_ptr
<MDnsListener
> listener1_
;
492 scoped_ptr
<MDnsListener
> listener2_
;
495 class MockListenerDelegate
: public MDnsListener::Delegate
{
497 MOCK_METHOD2(OnRecordUpdate
,
498 void(MDnsListener::UpdateType update
,
499 const RecordParsed
* records
));
500 MOCK_METHOD2(OnNsecRecord
, void(const std::string
&, unsigned));
501 MOCK_METHOD0(OnCachePurged
, void());
504 void MDnsTest::SetUp() {
505 test_client_
.reset(new MDnsClientImpl());
506 test_client_
->StartListening(&socket_factory_
);
509 void MDnsTest::SimulatePacketReceive(const uint8
* packet
, unsigned size
) {
510 socket_factory_
.SimulateReceive(packet
, size
);
513 void MDnsTest::ExpectPacket(const uint8
* packet
, unsigned size
) {
514 EXPECT_CALL(socket_factory_
, OnSendTo(MakeString(packet
, size
)))
518 void MDnsTest::DeleteTransaction() {
519 transaction_
.reset();
522 void MDnsTest::DeleteBothListeners() {
527 void MDnsTest::RunFor(base::TimeDelta time_period
) {
528 base::CancelableCallback
<void()> callback(base::Bind(&MDnsTest::Stop
,
529 base::Unretained(this)));
530 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
531 FROM_HERE
, callback
.callback(), time_period
);
533 base::MessageLoop::current()->Run();
537 void MDnsTest::Stop() {
538 base::MessageLoop::current()->Quit();
541 TEST_F(MDnsTest
, PassiveListeners
) {
542 StrictMock
<MockListenerDelegate
> delegate_privet
;
543 StrictMock
<MockListenerDelegate
> delegate_printer
;
545 PtrRecordCopyContainer record_privet
;
546 PtrRecordCopyContainer record_printer
;
548 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
549 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
550 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
551 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
553 ASSERT_TRUE(listener_privet
->Start());
554 ASSERT_TRUE(listener_printer
->Start());
556 // Send the same packet twice to ensure no records are double-counted.
558 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
562 &PtrRecordCopyContainer::SaveWithDummyArg
));
564 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
568 &PtrRecordCopyContainer::SaveWithDummyArg
));
571 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
572 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
574 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
575 "hello._privet._tcp.local"));
577 EXPECT_TRUE(record_printer
.IsRecordWith("_printer._tcp.local",
578 "hello._printer._tcp.local"));
580 listener_privet
.reset();
581 listener_printer
.reset();
584 TEST_F(MDnsTest
, PassiveListenersCacheCleanup
) {
585 StrictMock
<MockListenerDelegate
> delegate_privet
;
587 PtrRecordCopyContainer record_privet
;
588 PtrRecordCopyContainer record_privet2
;
590 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
591 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
593 ASSERT_TRUE(listener_privet
->Start());
595 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
599 &PtrRecordCopyContainer::SaveWithDummyArg
));
601 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
603 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
604 "hello._privet._tcp.local"));
606 // Expect record is removed when its TTL expires.
607 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
609 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop
),
610 Invoke(&record_privet2
,
611 &PtrRecordCopyContainer::SaveWithDummyArg
)));
613 RunFor(base::TimeDelta::FromSeconds(record_privet
.ttl() + 1));
615 EXPECT_TRUE(record_privet2
.IsRecordWith("_privet._tcp.local",
616 "hello._privet._tcp.local"));
619 // Ensure that the cleanup task scheduler won't schedule cleanup tasks in the
620 // past if the system clock creeps past the expiration time while in the
621 // cleanup dispatcher.
622 TEST_F(MDnsTest
, CacheCleanupWithShortTTL
) {
623 // Use a nonzero starting time as a base.
624 base::Time start_time
= base::Time() + base::TimeDelta::FromSeconds(1);
626 MockClock
* clock
= new MockClock
;
627 MockTimer
* timer
= new MockTimer
;
630 new MDnsClientImpl(make_scoped_ptr(clock
), make_scoped_ptr(timer
)));
631 test_client_
->StartListening(&socket_factory_
);
633 EXPECT_CALL(*timer
, StartObserver(_
, _
, _
)).Times(1);
634 EXPECT_CALL(*clock
, Now())
636 .WillRepeatedly(Return(start_time
))
637 .RetiresOnSaturation();
639 // Receive two records with different TTL values.
642 StrictMock
<MockListenerDelegate
> delegate_privet
;
643 StrictMock
<MockListenerDelegate
> delegate_printer
;
645 PtrRecordCopyContainer record_privet
;
646 PtrRecordCopyContainer record_printer
;
648 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
649 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
650 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
651 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
653 ASSERT_TRUE(listener_privet
->Start());
654 ASSERT_TRUE(listener_printer
->Start());
656 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
658 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
661 SimulatePacketReceive(kSamplePacket3
, sizeof(kSamplePacket3
));
663 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
666 // Set the clock to 2.0s, which should clean up the 'privet' record, but not
667 // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
668 // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
669 EXPECT_CALL(*clock
, Now())
670 .WillOnce(Return(start_time
+ base::TimeDelta::FromSeconds(4)))
671 .RetiresOnSaturation();
672 EXPECT_CALL(*clock
, Now())
673 .WillOnce(Return(start_time
+ base::TimeDelta::FromSeconds(2)))
674 .RetiresOnSaturation();
676 EXPECT_CALL(*timer
, StartObserver(_
, base::TimeDelta(), _
));
681 TEST_F(MDnsTest
, MalformedPacket
) {
682 StrictMock
<MockListenerDelegate
> delegate_printer
;
684 PtrRecordCopyContainer record_printer
;
686 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
687 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
689 ASSERT_TRUE(listener_printer
->Start());
691 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
695 &PtrRecordCopyContainer::SaveWithDummyArg
));
697 // First, send unsalvagable packet to ensure we can deal with it.
698 SimulatePacketReceive(kCorruptedPacketUnsalvagable
,
699 sizeof(kCorruptedPacketUnsalvagable
));
701 // Regression test: send a packet where the question cannot be read.
702 SimulatePacketReceive(kCorruptedPacketBadQuestion
,
703 sizeof(kCorruptedPacketBadQuestion
));
705 // Then send salvagable packet to ensure we can extract useful records.
706 SimulatePacketReceive(kCorruptedPacketSalvagable
,
707 sizeof(kCorruptedPacketSalvagable
));
709 EXPECT_TRUE(record_printer
.IsRecordWith("_printer._tcp.local",
710 "hello._printer._tcp.local"));
713 TEST_F(MDnsTest
, TransactionWithEmptyCache
) {
714 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
716 scoped_ptr
<MDnsTransaction
> transaction_privet
=
717 test_client_
->CreateTransaction(
718 dns_protocol::kTypePTR
, "_privet._tcp.local",
719 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
720 MDnsTransaction::SINGLE_RESULT
,
721 base::Bind(&MDnsTest::MockableRecordCallback
,
722 base::Unretained(this)));
724 ASSERT_TRUE(transaction_privet
->Start());
726 PtrRecordCopyContainer record_privet
;
728 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
730 .WillOnce(Invoke(&record_privet
,
731 &PtrRecordCopyContainer::SaveWithDummyArg
));
733 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
735 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
736 "hello._privet._tcp.local"));
739 TEST_F(MDnsTest
, TransactionCacheOnlyNoResult
) {
740 scoped_ptr
<MDnsTransaction
> transaction_privet
=
741 test_client_
->CreateTransaction(
742 dns_protocol::kTypePTR
, "_privet._tcp.local",
743 MDnsTransaction::QUERY_CACHE
| MDnsTransaction::SINGLE_RESULT
,
744 base::Bind(&MDnsTest::MockableRecordCallback
,
745 base::Unretained(this)));
748 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
, _
))
751 ASSERT_TRUE(transaction_privet
->Start());
754 TEST_F(MDnsTest
, TransactionWithCache
) {
755 // Listener to force the client to listen
756 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
757 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
758 dns_protocol::kTypeA
, "codereview.chromium.local", &delegate_irrelevant
);
760 ASSERT_TRUE(listener_irrelevant
->Start());
762 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
765 PtrRecordCopyContainer record_privet
;
767 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
768 .WillOnce(Invoke(&record_privet
,
769 &PtrRecordCopyContainer::SaveWithDummyArg
));
771 scoped_ptr
<MDnsTransaction
> transaction_privet
=
772 test_client_
->CreateTransaction(
773 dns_protocol::kTypePTR
, "_privet._tcp.local",
774 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
775 MDnsTransaction::SINGLE_RESULT
,
776 base::Bind(&MDnsTest::MockableRecordCallback
,
777 base::Unretained(this)));
779 ASSERT_TRUE(transaction_privet
->Start());
781 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
782 "hello._privet._tcp.local"));
785 TEST_F(MDnsTest
, AdditionalRecords
) {
786 StrictMock
<MockListenerDelegate
> delegate_privet
;
788 PtrRecordCopyContainer record_privet
;
790 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
791 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
793 ASSERT_TRUE(listener_privet
->Start());
795 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
799 &PtrRecordCopyContainer::SaveWithDummyArg
));
801 SimulatePacketReceive(kSamplePacketAdditionalOnly
,
802 sizeof(kSamplePacketAdditionalOnly
));
804 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
805 "hello._privet._tcp.local"));
808 TEST_F(MDnsTest
, TransactionTimeout
) {
809 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
811 scoped_ptr
<MDnsTransaction
> transaction_privet
=
812 test_client_
->CreateTransaction(
813 dns_protocol::kTypePTR
, "_privet._tcp.local",
814 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
815 MDnsTransaction::SINGLE_RESULT
,
816 base::Bind(&MDnsTest::MockableRecordCallback
,
817 base::Unretained(this)));
819 ASSERT_TRUE(transaction_privet
->Start());
822 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
, NULL
))
824 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop
));
826 RunFor(base::TimeDelta::FromSeconds(4));
829 TEST_F(MDnsTest
, TransactionMultipleRecords
) {
830 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
832 scoped_ptr
<MDnsTransaction
> transaction_privet
=
833 test_client_
->CreateTransaction(
834 dns_protocol::kTypePTR
, "_privet._tcp.local",
835 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
,
836 base::Bind(&MDnsTest::MockableRecordCallback
,
837 base::Unretained(this)));
839 ASSERT_TRUE(transaction_privet
->Start());
841 PtrRecordCopyContainer record_privet
;
842 PtrRecordCopyContainer record_privet2
;
844 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
846 .WillOnce(Invoke(&record_privet
,
847 &PtrRecordCopyContainer::SaveWithDummyArg
))
848 .WillOnce(Invoke(&record_privet2
,
849 &PtrRecordCopyContainer::SaveWithDummyArg
));
851 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
852 SimulatePacketReceive(kSamplePacket2
, sizeof(kSamplePacket2
));
854 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
855 "hello._privet._tcp.local"));
857 EXPECT_TRUE(record_privet2
.IsRecordWith("_privet._tcp.local",
858 "zzzzz._privet._tcp.local"));
860 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE
, NULL
))
861 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop
));
863 RunFor(base::TimeDelta::FromSeconds(4));
866 TEST_F(MDnsTest
, TransactionReentrantDelete
) {
867 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
869 transaction_
= test_client_
->CreateTransaction(
870 dns_protocol::kTypePTR
, "_privet._tcp.local",
871 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
872 MDnsTransaction::SINGLE_RESULT
,
873 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
875 ASSERT_TRUE(transaction_
->Start());
877 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
,
880 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction
),
881 InvokeWithoutArgs(this, &MDnsTest::Stop
)));
883 RunFor(base::TimeDelta::FromSeconds(4));
885 EXPECT_EQ(NULL
, transaction_
.get());
888 TEST_F(MDnsTest
, TransactionReentrantDeleteFromCache
) {
889 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
890 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
891 dns_protocol::kTypeA
, "codereview.chromium.local", &delegate_irrelevant
);
892 ASSERT_TRUE(listener_irrelevant
->Start());
894 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
896 transaction_
= test_client_
->CreateTransaction(
897 dns_protocol::kTypePTR
, "_privet._tcp.local",
898 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
,
899 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
901 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
903 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction
));
905 ASSERT_TRUE(transaction_
->Start());
907 EXPECT_EQ(NULL
, transaction_
.get());
910 TEST_F(MDnsTest
, TransactionReentrantCacheLookupStart
) {
911 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
913 scoped_ptr
<MDnsTransaction
> transaction1
= test_client_
->CreateTransaction(
914 dns_protocol::kTypePTR
, "_privet._tcp.local",
915 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
916 MDnsTransaction::SINGLE_RESULT
,
917 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
919 scoped_ptr
<MDnsTransaction
> transaction2
= test_client_
->CreateTransaction(
920 dns_protocol::kTypePTR
, "_printer._tcp.local",
921 MDnsTransaction::QUERY_CACHE
| MDnsTransaction::SINGLE_RESULT
,
922 base::Bind(&MDnsTest::MockableRecordCallback2
, base::Unretained(this)));
924 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD
,
928 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
,
931 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2
.get(),
932 &MDnsTransaction::Start
)));
934 ASSERT_TRUE(transaction1
->Start());
936 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
939 TEST_F(MDnsTest
, GoodbyePacketNotification
) {
940 StrictMock
<MockListenerDelegate
> delegate_privet
;
942 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
943 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
944 ASSERT_TRUE(listener_privet
->Start());
946 SimulatePacketReceive(kSamplePacketGoodbye
, sizeof(kSamplePacketGoodbye
));
948 RunFor(base::TimeDelta::FromSeconds(2));
951 TEST_F(MDnsTest
, GoodbyePacketRemoval
) {
952 StrictMock
<MockListenerDelegate
> delegate_privet
;
954 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
955 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
956 ASSERT_TRUE(listener_privet
->Start());
958 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
961 SimulatePacketReceive(kSamplePacket2
, sizeof(kSamplePacket2
));
963 SimulatePacketReceive(kSamplePacketGoodbye
, sizeof(kSamplePacketGoodbye
));
965 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
968 RunFor(base::TimeDelta::FromSeconds(2));
971 // In order to reliably test reentrant listener deletes, we create two listeners
972 // and have each of them delete both, so we're guaranteed to try and deliver a
973 // callback to at least one deleted listener.
975 TEST_F(MDnsTest
, ListenerReentrantDelete
) {
976 StrictMock
<MockListenerDelegate
> delegate_privet
;
978 listener1_
= test_client_
->CreateListener(
979 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
981 listener2_
= test_client_
->CreateListener(
982 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
984 ASSERT_TRUE(listener1_
->Start());
986 ASSERT_TRUE(listener2_
->Start());
988 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
990 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners
));
992 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
994 EXPECT_EQ(NULL
, listener1_
.get());
995 EXPECT_EQ(NULL
, listener2_
.get());
998 ACTION_P(SaveIPAddress
, ip_container
) {
999 ::testing::StaticAssertTypeEq
<const RecordParsed
*, arg1_type
>();
1000 ::testing::StaticAssertTypeEq
<IPAddressNumber
*, ip_container_type
>();
1002 *ip_container
= arg1
->template rdata
<ARecordRdata
>()->address();
1005 TEST_F(MDnsTest
, DoubleRecordDisagreeing
) {
1006 IPAddressNumber address
;
1007 StrictMock
<MockListenerDelegate
> delegate_privet
;
1009 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1010 dns_protocol::kTypeA
, "privet.local", &delegate_privet
);
1012 ASSERT_TRUE(listener_privet
->Start());
1014 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
1016 .WillOnce(SaveIPAddress(&address
));
1018 SimulatePacketReceive(kCorruptedPacketDoubleRecord
,
1019 sizeof(kCorruptedPacketDoubleRecord
));
1021 EXPECT_EQ("2.3.4.5", IPAddressToString(address
));
1024 TEST_F(MDnsTest
, NsecWithListener
) {
1025 StrictMock
<MockListenerDelegate
> delegate_privet
;
1026 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1027 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1029 // Test to make sure nsec callback is NOT called for PTR
1030 // (which is marked as existing).
1031 StrictMock
<MockListenerDelegate
> delegate_privet2
;
1032 scoped_ptr
<MDnsListener
> listener_privet2
= test_client_
->CreateListener(
1033 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet2
);
1035 ASSERT_TRUE(listener_privet
->Start());
1037 EXPECT_CALL(delegate_privet
,
1038 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA
));
1040 SimulatePacketReceive(kSamplePacketNsec
,
1041 sizeof(kSamplePacketNsec
));
1044 TEST_F(MDnsTest
, NsecWithTransactionFromNetwork
) {
1045 scoped_ptr
<MDnsTransaction
> transaction_privet
=
1046 test_client_
->CreateTransaction(
1047 dns_protocol::kTypeA
, "_privet._tcp.local",
1048 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1049 MDnsTransaction::SINGLE_RESULT
,
1050 base::Bind(&MDnsTest::MockableRecordCallback
,
1051 base::Unretained(this)));
1053 EXPECT_CALL(socket_factory_
, OnSendTo(_
)).Times(2);
1055 ASSERT_TRUE(transaction_privet
->Start());
1058 MockableRecordCallback(MDnsTransaction::RESULT_NSEC
, NULL
));
1060 SimulatePacketReceive(kSamplePacketNsec
,
1061 sizeof(kSamplePacketNsec
));
1064 TEST_F(MDnsTest
, NsecWithTransactionFromCache
) {
1065 // Force mDNS to listen.
1066 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
1067 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
1068 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_irrelevant
);
1069 listener_irrelevant
->Start();
1071 SimulatePacketReceive(kSamplePacketNsec
,
1072 sizeof(kSamplePacketNsec
));
1075 MockableRecordCallback(MDnsTransaction::RESULT_NSEC
, NULL
));
1077 scoped_ptr
<MDnsTransaction
> transaction_privet_a
=
1078 test_client_
->CreateTransaction(
1079 dns_protocol::kTypeA
, "_privet._tcp.local",
1080 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1081 MDnsTransaction::SINGLE_RESULT
,
1082 base::Bind(&MDnsTest::MockableRecordCallback
,
1083 base::Unretained(this)));
1085 ASSERT_TRUE(transaction_privet_a
->Start());
1087 // Test that a PTR transaction does NOT consider the same NSEC record to be a
1088 // valid answer to the query
1090 scoped_ptr
<MDnsTransaction
> transaction_privet_ptr
=
1091 test_client_
->CreateTransaction(
1092 dns_protocol::kTypePTR
, "_privet._tcp.local",
1093 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1094 MDnsTransaction::SINGLE_RESULT
,
1095 base::Bind(&MDnsTest::MockableRecordCallback
,
1096 base::Unretained(this)));
1098 EXPECT_CALL(socket_factory_
, OnSendTo(_
)).Times(2);
1100 ASSERT_TRUE(transaction_privet_ptr
->Start());
1103 TEST_F(MDnsTest
, NsecConflictRemoval
) {
1104 StrictMock
<MockListenerDelegate
> delegate_privet
;
1105 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1106 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1108 ASSERT_TRUE(listener_privet
->Start());
1110 const RecordParsed
* record1
;
1111 const RecordParsed
* record2
;
1113 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
1114 .WillOnce(SaveArg
<1>(&record1
));
1116 SimulatePacketReceive(kSamplePacketAPrivet
,
1117 sizeof(kSamplePacketAPrivet
));
1119 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
1120 .WillOnce(SaveArg
<1>(&record2
));
1122 EXPECT_CALL(delegate_privet
,
1123 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA
));
1125 SimulatePacketReceive(kSamplePacketNsec
,
1126 sizeof(kSamplePacketNsec
));
1128 EXPECT_EQ(record1
, record2
);
1132 TEST_F(MDnsTest
, RefreshQuery
) {
1133 StrictMock
<MockListenerDelegate
> delegate_privet
;
1134 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1135 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1137 listener_privet
->SetActiveRefresh(true);
1138 ASSERT_TRUE(listener_privet
->Start());
1140 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
));
1142 SimulatePacketReceive(kSamplePacketAPrivet
,
1143 sizeof(kSamplePacketAPrivet
));
1145 // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2
1146 // scheduled refresh queries.
1147 EXPECT_CALL(socket_factory_
, OnSendTo(
1148 MakeString(kQueryPacketPrivetA
, sizeof(kQueryPacketPrivetA
))))
1151 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
));
1153 RunFor(base::TimeDelta::FromSeconds(6));
1156 // Note: These tests assume that the ipv4 socket will always be created first.
1157 // This is a simplifying assumption based on the way the code works now.
1158 class SimpleMockSocketFactory
: public MDnsSocketFactory
{
1160 void CreateSockets(ScopedVector
<DatagramServerSocket
>* sockets
) override
{
1162 sockets
->swap(sockets_
);
1165 void PushSocket(DatagramServerSocket
* socket
) {
1166 sockets_
.push_back(socket
);
1170 ScopedVector
<DatagramServerSocket
> sockets_
;
1173 class MockMDnsConnectionDelegate
: public MDnsConnection::Delegate
{
1175 virtual void HandlePacket(DnsResponse
* response
, int size
) {
1176 HandlePacketInternal(std::string(response
->io_buffer()->data(), size
));
1179 MOCK_METHOD1(HandlePacketInternal
, void(std::string packet
));
1181 MOCK_METHOD1(OnConnectionError
, void(int error
));
1184 class MDnsConnectionTest
: public ::testing::Test
{
1186 MDnsConnectionTest() : connection_(&delegate_
) {
1190 // Follow successful connection initialization.
1191 void SetUp() override
{
1192 socket_ipv4_
= new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4
);
1193 socket_ipv6_
= new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6
);
1194 factory_
.PushSocket(socket_ipv6_
);
1195 factory_
.PushSocket(socket_ipv4_
);
1196 sample_packet_
= MakeString(kSamplePacket1
, sizeof(kSamplePacket1
));
1197 sample_buffer_
= new StringIOBuffer(sample_packet_
);
1200 bool InitConnection() {
1201 return connection_
.Init(&factory_
);
1204 StrictMock
<MockMDnsConnectionDelegate
> delegate_
;
1206 MockMDnsDatagramServerSocket
* socket_ipv4_
;
1207 MockMDnsDatagramServerSocket
* socket_ipv6_
;
1208 SimpleMockSocketFactory factory_
;
1209 MDnsConnection connection_
;
1210 TestCompletionCallback callback_
;
1211 std::string sample_packet_
;
1212 scoped_refptr
<IOBuffer
> sample_buffer_
;
1215 TEST_F(MDnsConnectionTest
, ReceiveSynchronous
) {
1216 socket_ipv6_
->SetResponsePacket(sample_packet_
);
1217 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1218 .WillOnce(Return(ERR_IO_PENDING
));
1219 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1221 Invoke(socket_ipv6_
, &MockMDnsDatagramServerSocket::HandleRecvNow
))
1222 .WillOnce(Return(ERR_IO_PENDING
));
1224 EXPECT_CALL(delegate_
, HandlePacketInternal(sample_packet_
));
1225 ASSERT_TRUE(InitConnection());
1228 TEST_F(MDnsConnectionTest
, ReceiveAsynchronous
) {
1229 socket_ipv6_
->SetResponsePacket(sample_packet_
);
1231 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1232 .WillOnce(Return(ERR_IO_PENDING
));
1233 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1236 Invoke(socket_ipv6_
, &MockMDnsDatagramServerSocket::HandleRecvLater
))
1237 .WillOnce(Return(ERR_IO_PENDING
));
1239 ASSERT_TRUE(InitConnection());
1241 EXPECT_CALL(delegate_
, HandlePacketInternal(sample_packet_
));
1243 base::MessageLoop::current()->RunUntilIdle();
1246 TEST_F(MDnsConnectionTest
, Error
) {
1247 CompletionCallback callback
;
1249 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1250 .WillOnce(Return(ERR_IO_PENDING
));
1251 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1252 .WillOnce(DoAll(SaveArg
<3>(&callback
), Return(ERR_IO_PENDING
)));
1254 ASSERT_TRUE(InitConnection());
1256 EXPECT_CALL(delegate_
, OnConnectionError(ERR_SOCKET_NOT_CONNECTED
));
1257 callback
.Run(ERR_SOCKET_NOT_CONNECTED
);
1258 base::MessageLoop::current()->RunUntilIdle();
1261 class MDnsConnectionSendTest
: public MDnsConnectionTest
{
1263 void SetUp() override
{
1264 MDnsConnectionTest::SetUp();
1265 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1266 .WillOnce(Return(ERR_IO_PENDING
));
1267 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1268 .WillOnce(Return(ERR_IO_PENDING
));
1269 EXPECT_TRUE(InitConnection());
1273 TEST_F(MDnsConnectionSendTest
, Send
) {
1274 EXPECT_CALL(*socket_ipv4_
,
1275 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
));
1276 EXPECT_CALL(*socket_ipv6_
,
1277 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
));
1279 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1282 TEST_F(MDnsConnectionSendTest
, SendError
) {
1283 CompletionCallback callback
;
1285 EXPECT_CALL(*socket_ipv4_
,
1286 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
));
1287 EXPECT_CALL(*socket_ipv6_
,
1288 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1289 .WillOnce(DoAll(SaveArg
<2>(&callback
), Return(ERR_SOCKET_NOT_CONNECTED
)));
1291 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1292 EXPECT_CALL(delegate_
, OnConnectionError(ERR_SOCKET_NOT_CONNECTED
));
1293 base::MessageLoop::current()->RunUntilIdle();
1296 TEST_F(MDnsConnectionSendTest
, SendQueued
) {
1297 // Send data immediately.
1298 EXPECT_CALL(*socket_ipv4_
,
1299 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
))
1301 .WillRepeatedly(Return(OK
));
1303 CompletionCallback callback
;
1304 // Delay sending data. Only the first call should be made.
1305 EXPECT_CALL(*socket_ipv6_
,
1306 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1307 .WillOnce(DoAll(SaveArg
<2>(&callback
), Return(ERR_IO_PENDING
)));
1309 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1310 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1312 // The second IPv6 packed is not sent yet.
1313 EXPECT_CALL(*socket_ipv4_
,
1314 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
))
1316 // Expect call for the second IPv6 packed.
1317 EXPECT_CALL(*socket_ipv6_
,
1318 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1319 .WillOnce(Return(OK
));