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/memory/ref_counted.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/time/clock.h"
10 #include "base/time/default_clock.h"
11 #include "base/timer/mock_timer.h"
12 #include "net/base/rand_callback.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/dns/mdns_client_impl.h"
15 #include "net/dns/mock_mdns_socket_factory.h"
16 #include "net/dns/record_rdata.h"
17 #include "net/udp/udp_client_socket.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using ::testing::Invoke
;
22 using ::testing::InvokeWithoutArgs
;
23 using ::testing::StrictMock
;
24 using ::testing::NiceMock
;
25 using ::testing::Exactly
;
26 using ::testing::Return
;
27 using ::testing::SaveArg
;
34 const uint8 kSamplePacket1
[] = {
36 0x00, 0x00, // ID is zeroed out
37 0x81, 0x80, // Standard query response, RA, no error
38 0x00, 0x00, // No questions (for simplicity)
39 0x00, 0x02, // 2 RRs (answers)
40 0x00, 0x00, // 0 authority RRs
41 0x00, 0x00, // 0 additional RRs
44 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
45 0x04, '_', 't', 'c', 'p',
46 0x05, 'l', 'o', 'c', 'a', 'l',
48 0x00, 0x0c, // TYPE is PTR.
49 0x00, 0x01, // CLASS is IN.
50 0x00, 0x00, // TTL (4 bytes) is 1 second;
52 0x00, 0x08, // RDLENGTH is 8 bytes.
53 0x05, 'h', 'e', 'l', 'l', 'o',
57 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
58 0xc0, 0x14, // Pointer to "._tcp.local"
59 0x00, 0x0c, // TYPE is PTR.
60 0x00, 0x01, // CLASS is IN.
61 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
63 0x00, 0x08, // RDLENGTH is 8 bytes.
64 0x05, 'h', 'e', 'l', 'l', 'o',
68 const uint8 kCorruptedPacketBadQuestion
[] = {
70 0x00, 0x00, // ID is zeroed out
71 0x81, 0x80, // Standard query response, RA, no error
72 0x00, 0x01, // One question
73 0x00, 0x02, // 2 RRs (answers)
74 0x00, 0x00, // 0 authority RRs
75 0x00, 0x00, // 0 additional RRs
77 // Question is corrupted and cannot be read.
78 0x99, 'h', 'e', 'l', 'l', 'o',
84 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
85 0x04, '_', 't', 'c', 'p',
86 0x05, 'l', 'o', 'c', 'a', 'l',
88 0x00, 0x0c, // TYPE is PTR.
89 0x00, 0x01, // CLASS is IN.
90 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
92 0x00, 0x99, // RDLENGTH is impossible
93 0x05, 'h', 'e', 'l', 'l', 'o',
97 0x08, '_', 'p', 'r', // Useless trailing data.
100 const uint8 kCorruptedPacketUnsalvagable
[] = {
102 0x00, 0x00, // ID is zeroed out
103 0x81, 0x80, // Standard query response, RA, no error
104 0x00, 0x00, // No questions (for simplicity)
105 0x00, 0x02, // 2 RRs (answers)
106 0x00, 0x00, // 0 authority RRs
107 0x00, 0x00, // 0 additional RRs
110 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
111 0x04, '_', 't', 'c', 'p',
112 0x05, 'l', 'o', 'c', 'a', 'l',
114 0x00, 0x0c, // TYPE is PTR.
115 0x00, 0x01, // CLASS is IN.
116 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
118 0x00, 0x99, // RDLENGTH is impossible
119 0x05, 'h', 'e', 'l', 'l', 'o',
123 0x08, '_', 'p', 'r', // Useless trailing data.
126 const uint8 kCorruptedPacketDoubleRecord
[] = {
128 0x00, 0x00, // ID is zeroed out
129 0x81, 0x80, // Standard query response, RA, no error
130 0x00, 0x00, // No questions (for simplicity)
131 0x00, 0x02, // 2 RRs (answers)
132 0x00, 0x00, // 0 authority RRs
133 0x00, 0x00, // 0 additional RRs
136 0x06, 'p', 'r', 'i', 'v', 'e', 't',
137 0x05, 'l', 'o', 'c', 'a', 'l',
139 0x00, 0x01, // TYPE is A.
140 0x00, 0x01, // CLASS is IN.
141 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
143 0x00, 0x04, // RDLENGTH is 4
147 // Answer 2 -- Same key
148 0x06, 'p', 'r', 'i', 'v', 'e', 't',
149 0x05, 'l', 'o', 'c', 'a', 'l',
151 0x00, 0x01, // TYPE is A.
152 0x00, 0x01, // CLASS is IN.
153 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
155 0x00, 0x04, // RDLENGTH is 4
160 const uint8 kCorruptedPacketSalvagable
[] = {
162 0x00, 0x00, // ID is zeroed out
163 0x81, 0x80, // Standard query response, RA, no error
164 0x00, 0x00, // No questions (for simplicity)
165 0x00, 0x02, // 2 RRs (answers)
166 0x00, 0x00, // 0 authority RRs
167 0x00, 0x00, // 0 additional RRs
170 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
171 0x04, '_', 't', 'c', 'p',
172 0x05, 'l', 'o', 'c', 'a', 'l',
174 0x00, 0x0c, // TYPE is PTR.
175 0x00, 0x01, // CLASS is IN.
176 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
178 0x00, 0x08, // RDLENGTH is 8 bytes.
179 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
183 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
184 0xc0, 0x14, // Pointer to "._tcp.local"
185 0x00, 0x0c, // TYPE is PTR.
186 0x00, 0x01, // CLASS is IN.
187 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
189 0x00, 0x08, // RDLENGTH is 8 bytes.
190 0x05, 'h', 'e', 'l', 'l', 'o',
194 const uint8 kSamplePacket2
[] = {
196 0x00, 0x00, // ID is zeroed out
197 0x81, 0x80, // Standard query response, RA, no error
198 0x00, 0x00, // No questions (for simplicity)
199 0x00, 0x02, // 2 RRs (answers)
200 0x00, 0x00, // 0 authority RRs
201 0x00, 0x00, // 0 additional RRs
204 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
205 0x04, '_', 't', 'c', 'p',
206 0x05, 'l', 'o', 'c', 'a', 'l',
208 0x00, 0x0c, // TYPE is PTR.
209 0x00, 0x01, // CLASS is IN.
210 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
212 0x00, 0x08, // RDLENGTH is 8 bytes.
213 0x05, 'z', 'z', 'z', 'z', 'z',
217 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
218 0xc0, 0x14, // Pointer to "._tcp.local"
219 0x00, 0x0c, // TYPE is PTR.
220 0x00, 0x01, // CLASS is IN.
221 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
223 0x00, 0x08, // RDLENGTH is 8 bytes.
224 0x05, 'z', 'z', 'z', 'z', 'z',
228 const uint8 kSamplePacket3
[] = {
230 0x00, 0x00, // ID is zeroed out
231 0x81, 0x80, // Standard query response, RA, no error
232 0x00, 0x00, // No questions (for simplicity)
233 0x00, 0x02, // 2 RRs (answers)
234 0x00, 0x00, // 0 authority RRs
235 0x00, 0x00, // 0 additional RRs
238 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', //
239 0x04, '_', 't', 'c', 'p', //
240 0x05, 'l', 'o', 'c', 'a', 'l', //
241 0x00, 0x00, 0x0c, // TYPE is PTR.
242 0x00, 0x01, // CLASS is IN.
243 0x00, 0x00, // TTL (4 bytes) is 1 second;
245 0x00, 0x08, // RDLENGTH is 8 bytes.
246 0x05, 'h', 'e', 'l', 'l', 'o', //
250 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', //
251 0xc0, 0x14, // Pointer to "._tcp.local"
252 0x00, 0x0c, // TYPE is PTR.
253 0x00, 0x01, // CLASS is IN.
254 0x00, 0x00, // TTL (4 bytes) is 3 seconds.
256 0x00, 0x08, // RDLENGTH is 8 bytes.
257 0x05, 'h', 'e', 'l', 'l', 'o', //
260 const uint8 kQueryPacketPrivet
[] = {
262 0x00, 0x00, // ID is zeroed out
263 0x00, 0x00, // No flags.
264 0x00, 0x01, // One question.
265 0x00, 0x00, // 0 RRs (answers)
266 0x00, 0x00, // 0 authority RRs
267 0x00, 0x00, // 0 additional RRs
270 // This part is echoed back from the respective query.
271 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
272 0x04, '_', 't', 'c', 'p',
273 0x05, 'l', 'o', 'c', 'a', 'l',
275 0x00, 0x0c, // TYPE is PTR.
276 0x00, 0x01, // CLASS is IN.
279 const uint8 kQueryPacketPrivetA
[] = {
281 0x00, 0x00, // ID is zeroed out
282 0x00, 0x00, // No flags.
283 0x00, 0x01, // One question.
284 0x00, 0x00, // 0 RRs (answers)
285 0x00, 0x00, // 0 authority RRs
286 0x00, 0x00, // 0 additional RRs
289 // This part is echoed back from the respective query.
290 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
291 0x04, '_', 't', 'c', 'p',
292 0x05, 'l', 'o', 'c', 'a', 'l',
294 0x00, 0x01, // TYPE is A.
295 0x00, 0x01, // CLASS is IN.
298 const uint8 kSamplePacketAdditionalOnly
[] = {
300 0x00, 0x00, // ID is zeroed out
301 0x81, 0x80, // Standard query response, RA, no error
302 0x00, 0x00, // No questions (for simplicity)
303 0x00, 0x00, // 2 RRs (answers)
304 0x00, 0x00, // 0 authority RRs
305 0x00, 0x01, // 0 additional RRs
308 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
309 0x04, '_', 't', 'c', 'p',
310 0x05, 'l', 'o', 'c', 'a', 'l',
312 0x00, 0x0c, // TYPE is PTR.
313 0x00, 0x01, // CLASS is IN.
314 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
316 0x00, 0x08, // RDLENGTH is 8 bytes.
317 0x05, 'h', 'e', 'l', 'l', 'o',
321 const uint8 kSamplePacketNsec
[] = {
323 0x00, 0x00, // ID is zeroed out
324 0x81, 0x80, // Standard query response, RA, no error
325 0x00, 0x00, // No questions (for simplicity)
326 0x00, 0x01, // 1 RR (answers)
327 0x00, 0x00, // 0 authority RRs
328 0x00, 0x00, // 0 additional RRs
331 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
332 0x04, '_', 't', 'c', 'p',
333 0x05, 'l', 'o', 'c', 'a', 'l',
335 0x00, 0x2f, // TYPE is NSEC.
336 0x00, 0x01, // CLASS is IN.
337 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
339 0x00, 0x06, // RDLENGTH is 6 bytes.
341 0x00, 0x02, 0x00, 0x08 // Only A record present
344 const uint8 kSamplePacketAPrivet
[] = {
346 0x00, 0x00, // ID is zeroed out
347 0x81, 0x80, // Standard query response, RA, no error
348 0x00, 0x00, // No questions (for simplicity)
349 0x00, 0x01, // 1 RR (answers)
350 0x00, 0x00, // 0 authority RRs
351 0x00, 0x00, // 0 additional RRs
354 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
355 0x04, '_', 't', 'c', 'p',
356 0x05, 'l', 'o', 'c', 'a', 'l',
358 0x00, 0x01, // TYPE is A.
359 0x00, 0x01, // CLASS is IN.
360 0x00, 0x00, // TTL (4 bytes) is 5 seconds
362 0x00, 0x04, // RDLENGTH is 4 bytes.
367 const uint8 kSamplePacketGoodbye
[] = {
369 0x00, 0x00, // ID is zeroed out
370 0x81, 0x80, // Standard query response, RA, no error
371 0x00, 0x00, // No questions (for simplicity)
372 0x00, 0x01, // 2 RRs (answers)
373 0x00, 0x00, // 0 authority RRs
374 0x00, 0x00, // 0 additional RRs
377 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
378 0x04, '_', 't', 'c', 'p',
379 0x05, 'l', 'o', 'c', 'a', 'l',
381 0x00, 0x0c, // TYPE is PTR.
382 0x00, 0x01, // CLASS is IN.
383 0x00, 0x00, // TTL (4 bytes) is zero;
385 0x00, 0x08, // RDLENGTH is 8 bytes.
386 0x05, 'z', 'z', 'z', 'z', 'z',
390 std::string
MakeString(const uint8
* data
, unsigned size
) {
391 return std::string(reinterpret_cast<const char*>(data
), size
);
394 class PtrRecordCopyContainer
{
396 PtrRecordCopyContainer() {}
397 ~PtrRecordCopyContainer() {}
399 bool is_set() const { return set_
; }
401 void SaveWithDummyArg(int unused
, const RecordParsed
* value
) {
405 void Save(const RecordParsed
* value
) {
407 name_
= value
->name();
408 ptrdomain_
= value
->rdata
<PtrRecordRdata
>()->ptrdomain();
412 bool IsRecordWith(std::string name
, std::string ptrdomain
) {
413 return set_
&& name_
== name
&& ptrdomain_
== ptrdomain
;
416 const std::string
& name() { return name_
; }
417 const std::string
& ptrdomain() { return ptrdomain_
; }
418 int ttl() { return ttl_
; }
423 std::string ptrdomain_
;
427 class MockClock
: public base::DefaultClock
{
429 MockClock() : base::DefaultClock() {}
430 virtual ~MockClock() {}
432 MOCK_METHOD0(Now
, base::Time());
435 DISALLOW_COPY_AND_ASSIGN(MockClock
);
438 class MockTimer
: public base::MockTimer
{
440 MockTimer() : base::MockTimer(false, false) {}
443 void Start(const tracked_objects::Location
& posted_from
,
444 base::TimeDelta delay
,
445 const base::Closure
& user_task
) {
446 StartObserver(posted_from
, delay
, user_task
);
447 base::MockTimer::Start(posted_from
, delay
, user_task
);
450 // StartObserver is invoked when MockTimer::Start() is called.
451 // Does not replace the behavior of MockTimer::Start().
452 MOCK_METHOD3(StartObserver
,
453 void(const tracked_objects::Location
& posted_from
,
454 base::TimeDelta delay
,
455 const base::Closure
& user_task
));
458 DISALLOW_COPY_AND_ASSIGN(MockTimer
);
463 class MDnsTest
: public ::testing::Test
{
465 void SetUp() override
;
466 void DeleteTransaction();
467 void DeleteBothListeners();
468 void RunFor(base::TimeDelta time_period
);
471 MOCK_METHOD2(MockableRecordCallback
, void(MDnsTransaction::Result result
,
472 const RecordParsed
* record
));
474 MOCK_METHOD2(MockableRecordCallback2
, void(MDnsTransaction::Result result
,
475 const RecordParsed
* record
));
478 void ExpectPacket(const uint8
* packet
, unsigned size
);
479 void SimulatePacketReceive(const uint8
* packet
, unsigned size
);
481 scoped_ptr
<MDnsClientImpl
> test_client_
;
482 IPEndPoint mdns_ipv4_endpoint_
;
483 StrictMock
<MockMDnsSocketFactory
> socket_factory_
;
485 // Transactions and listeners that can be deleted by class methods for
487 scoped_ptr
<MDnsTransaction
> transaction_
;
488 scoped_ptr
<MDnsListener
> listener1_
;
489 scoped_ptr
<MDnsListener
> listener2_
;
492 class MockListenerDelegate
: public MDnsListener::Delegate
{
494 MOCK_METHOD2(OnRecordUpdate
,
495 void(MDnsListener::UpdateType update
,
496 const RecordParsed
* records
));
497 MOCK_METHOD2(OnNsecRecord
, void(const std::string
&, unsigned));
498 MOCK_METHOD0(OnCachePurged
, void());
501 void MDnsTest::SetUp() {
502 test_client_
.reset(new MDnsClientImpl());
503 test_client_
->StartListening(&socket_factory_
);
506 void MDnsTest::SimulatePacketReceive(const uint8
* packet
, unsigned size
) {
507 socket_factory_
.SimulateReceive(packet
, size
);
510 void MDnsTest::ExpectPacket(const uint8
* packet
, unsigned size
) {
511 EXPECT_CALL(socket_factory_
, OnSendTo(MakeString(packet
, size
)))
515 void MDnsTest::DeleteTransaction() {
516 transaction_
.reset();
519 void MDnsTest::DeleteBothListeners() {
524 void MDnsTest::RunFor(base::TimeDelta time_period
) {
525 base::CancelableCallback
<void()> callback(base::Bind(&MDnsTest::Stop
,
526 base::Unretained(this)));
527 base::MessageLoop::current()->PostDelayedTask(
528 FROM_HERE
, callback
.callback(), time_period
);
530 base::MessageLoop::current()->Run();
534 void MDnsTest::Stop() {
535 base::MessageLoop::current()->Quit();
538 TEST_F(MDnsTest
, PassiveListeners
) {
539 StrictMock
<MockListenerDelegate
> delegate_privet
;
540 StrictMock
<MockListenerDelegate
> delegate_printer
;
542 PtrRecordCopyContainer record_privet
;
543 PtrRecordCopyContainer record_printer
;
545 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
546 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
547 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
548 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
550 ASSERT_TRUE(listener_privet
->Start());
551 ASSERT_TRUE(listener_printer
->Start());
553 // Send the same packet twice to ensure no records are double-counted.
555 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
559 &PtrRecordCopyContainer::SaveWithDummyArg
));
561 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
565 &PtrRecordCopyContainer::SaveWithDummyArg
));
568 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
569 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
571 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
572 "hello._privet._tcp.local"));
574 EXPECT_TRUE(record_printer
.IsRecordWith("_printer._tcp.local",
575 "hello._printer._tcp.local"));
577 listener_privet
.reset();
578 listener_printer
.reset();
581 TEST_F(MDnsTest
, PassiveListenersCacheCleanup
) {
582 StrictMock
<MockListenerDelegate
> delegate_privet
;
584 PtrRecordCopyContainer record_privet
;
585 PtrRecordCopyContainer record_privet2
;
587 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
588 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
590 ASSERT_TRUE(listener_privet
->Start());
592 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
596 &PtrRecordCopyContainer::SaveWithDummyArg
));
598 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
600 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
601 "hello._privet._tcp.local"));
603 // Expect record is removed when its TTL expires.
604 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
606 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop
),
607 Invoke(&record_privet2
,
608 &PtrRecordCopyContainer::SaveWithDummyArg
)));
610 RunFor(base::TimeDelta::FromSeconds(record_privet
.ttl() + 1));
612 EXPECT_TRUE(record_privet2
.IsRecordWith("_privet._tcp.local",
613 "hello._privet._tcp.local"));
616 // Ensure that the cleanup task scheduler won't schedule cleanup tasks in the
617 // past if the system clock creeps past the expiration time while in the
618 // cleanup dispatcher.
619 TEST_F(MDnsTest
, CacheCleanupWithShortTTL
) {
620 // Use a nonzero starting time as a base.
621 base::Time start_time
= base::Time() + base::TimeDelta::FromSeconds(1);
623 MockClock
* clock
= new MockClock
;
624 MockTimer
* timer
= new MockTimer
;
627 new MDnsClientImpl(make_scoped_ptr(clock
), make_scoped_ptr(timer
)));
628 test_client_
->StartListening(&socket_factory_
);
630 EXPECT_CALL(*timer
, StartObserver(_
, _
, _
)).Times(1);
631 EXPECT_CALL(*clock
, Now())
633 .WillRepeatedly(Return(start_time
))
634 .RetiresOnSaturation();
636 // Receive two records with different TTL values.
639 StrictMock
<MockListenerDelegate
> delegate_privet
;
640 StrictMock
<MockListenerDelegate
> delegate_printer
;
642 PtrRecordCopyContainer record_privet
;
643 PtrRecordCopyContainer record_printer
;
645 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
646 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
647 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
648 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
650 ASSERT_TRUE(listener_privet
->Start());
651 ASSERT_TRUE(listener_printer
->Start());
653 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
655 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
658 SimulatePacketReceive(kSamplePacket3
, sizeof(kSamplePacket3
));
660 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
663 // Set the clock to 2.0s, which should clean up the 'privet' record, but not
664 // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
665 // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
666 EXPECT_CALL(*clock
, Now())
667 .WillOnce(Return(start_time
+ base::TimeDelta::FromSeconds(4)))
668 .RetiresOnSaturation();
669 EXPECT_CALL(*clock
, Now())
670 .WillOnce(Return(start_time
+ base::TimeDelta::FromSeconds(2)))
671 .RetiresOnSaturation();
673 EXPECT_CALL(*timer
, StartObserver(_
, base::TimeDelta(), _
));
678 TEST_F(MDnsTest
, MalformedPacket
) {
679 StrictMock
<MockListenerDelegate
> delegate_printer
;
681 PtrRecordCopyContainer record_printer
;
683 scoped_ptr
<MDnsListener
> listener_printer
= test_client_
->CreateListener(
684 dns_protocol::kTypePTR
, "_printer._tcp.local", &delegate_printer
);
686 ASSERT_TRUE(listener_printer
->Start());
688 EXPECT_CALL(delegate_printer
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
692 &PtrRecordCopyContainer::SaveWithDummyArg
));
694 // First, send unsalvagable packet to ensure we can deal with it.
695 SimulatePacketReceive(kCorruptedPacketUnsalvagable
,
696 sizeof(kCorruptedPacketUnsalvagable
));
698 // Regression test: send a packet where the question cannot be read.
699 SimulatePacketReceive(kCorruptedPacketBadQuestion
,
700 sizeof(kCorruptedPacketBadQuestion
));
702 // Then send salvagable packet to ensure we can extract useful records.
703 SimulatePacketReceive(kCorruptedPacketSalvagable
,
704 sizeof(kCorruptedPacketSalvagable
));
706 EXPECT_TRUE(record_printer
.IsRecordWith("_printer._tcp.local",
707 "hello._printer._tcp.local"));
710 TEST_F(MDnsTest
, TransactionWithEmptyCache
) {
711 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
713 scoped_ptr
<MDnsTransaction
> transaction_privet
=
714 test_client_
->CreateTransaction(
715 dns_protocol::kTypePTR
, "_privet._tcp.local",
716 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
717 MDnsTransaction::SINGLE_RESULT
,
718 base::Bind(&MDnsTest::MockableRecordCallback
,
719 base::Unretained(this)));
721 ASSERT_TRUE(transaction_privet
->Start());
723 PtrRecordCopyContainer record_privet
;
725 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
727 .WillOnce(Invoke(&record_privet
,
728 &PtrRecordCopyContainer::SaveWithDummyArg
));
730 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
732 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
733 "hello._privet._tcp.local"));
736 TEST_F(MDnsTest
, TransactionCacheOnlyNoResult
) {
737 scoped_ptr
<MDnsTransaction
> transaction_privet
=
738 test_client_
->CreateTransaction(
739 dns_protocol::kTypePTR
, "_privet._tcp.local",
740 MDnsTransaction::QUERY_CACHE
| MDnsTransaction::SINGLE_RESULT
,
741 base::Bind(&MDnsTest::MockableRecordCallback
,
742 base::Unretained(this)));
745 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
, _
))
748 ASSERT_TRUE(transaction_privet
->Start());
751 TEST_F(MDnsTest
, TransactionWithCache
) {
752 // Listener to force the client to listen
753 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
754 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
755 dns_protocol::kTypeA
, "codereview.chromium.local", &delegate_irrelevant
);
757 ASSERT_TRUE(listener_irrelevant
->Start());
759 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
762 PtrRecordCopyContainer record_privet
;
764 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
765 .WillOnce(Invoke(&record_privet
,
766 &PtrRecordCopyContainer::SaveWithDummyArg
));
768 scoped_ptr
<MDnsTransaction
> transaction_privet
=
769 test_client_
->CreateTransaction(
770 dns_protocol::kTypePTR
, "_privet._tcp.local",
771 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
772 MDnsTransaction::SINGLE_RESULT
,
773 base::Bind(&MDnsTest::MockableRecordCallback
,
774 base::Unretained(this)));
776 ASSERT_TRUE(transaction_privet
->Start());
778 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
779 "hello._privet._tcp.local"));
782 TEST_F(MDnsTest
, AdditionalRecords
) {
783 StrictMock
<MockListenerDelegate
> delegate_privet
;
785 PtrRecordCopyContainer record_privet
;
787 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
788 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
790 ASSERT_TRUE(listener_privet
->Start());
792 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
796 &PtrRecordCopyContainer::SaveWithDummyArg
));
798 SimulatePacketReceive(kSamplePacketAdditionalOnly
,
799 sizeof(kSamplePacketAdditionalOnly
));
801 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
802 "hello._privet._tcp.local"));
805 TEST_F(MDnsTest
, TransactionTimeout
) {
806 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
808 scoped_ptr
<MDnsTransaction
> transaction_privet
=
809 test_client_
->CreateTransaction(
810 dns_protocol::kTypePTR
, "_privet._tcp.local",
811 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
812 MDnsTransaction::SINGLE_RESULT
,
813 base::Bind(&MDnsTest::MockableRecordCallback
,
814 base::Unretained(this)));
816 ASSERT_TRUE(transaction_privet
->Start());
819 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
, NULL
))
821 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop
));
823 RunFor(base::TimeDelta::FromSeconds(4));
826 TEST_F(MDnsTest
, TransactionMultipleRecords
) {
827 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
829 scoped_ptr
<MDnsTransaction
> transaction_privet
=
830 test_client_
->CreateTransaction(
831 dns_protocol::kTypePTR
, "_privet._tcp.local",
832 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
,
833 base::Bind(&MDnsTest::MockableRecordCallback
,
834 base::Unretained(this)));
836 ASSERT_TRUE(transaction_privet
->Start());
838 PtrRecordCopyContainer record_privet
;
839 PtrRecordCopyContainer record_privet2
;
841 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
843 .WillOnce(Invoke(&record_privet
,
844 &PtrRecordCopyContainer::SaveWithDummyArg
))
845 .WillOnce(Invoke(&record_privet2
,
846 &PtrRecordCopyContainer::SaveWithDummyArg
));
848 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
849 SimulatePacketReceive(kSamplePacket2
, sizeof(kSamplePacket2
));
851 EXPECT_TRUE(record_privet
.IsRecordWith("_privet._tcp.local",
852 "hello._privet._tcp.local"));
854 EXPECT_TRUE(record_privet2
.IsRecordWith("_privet._tcp.local",
855 "zzzzz._privet._tcp.local"));
857 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE
, NULL
))
858 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop
));
860 RunFor(base::TimeDelta::FromSeconds(4));
863 TEST_F(MDnsTest
, TransactionReentrantDelete
) {
864 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
866 transaction_
= test_client_
->CreateTransaction(
867 dns_protocol::kTypePTR
, "_privet._tcp.local",
868 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
869 MDnsTransaction::SINGLE_RESULT
,
870 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
872 ASSERT_TRUE(transaction_
->Start());
874 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS
,
877 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction
),
878 InvokeWithoutArgs(this, &MDnsTest::Stop
)));
880 RunFor(base::TimeDelta::FromSeconds(4));
882 EXPECT_EQ(NULL
, transaction_
.get());
885 TEST_F(MDnsTest
, TransactionReentrantDeleteFromCache
) {
886 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
887 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
888 dns_protocol::kTypeA
, "codereview.chromium.local", &delegate_irrelevant
);
889 ASSERT_TRUE(listener_irrelevant
->Start());
891 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
893 transaction_
= test_client_
->CreateTransaction(
894 dns_protocol::kTypePTR
, "_privet._tcp.local",
895 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
,
896 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
898 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
, _
))
900 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction
));
902 ASSERT_TRUE(transaction_
->Start());
904 EXPECT_EQ(NULL
, transaction_
.get());
907 TEST_F(MDnsTest
, TransactionReentrantCacheLookupStart
) {
908 ExpectPacket(kQueryPacketPrivet
, sizeof(kQueryPacketPrivet
));
910 scoped_ptr
<MDnsTransaction
> transaction1
= test_client_
->CreateTransaction(
911 dns_protocol::kTypePTR
, "_privet._tcp.local",
912 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
913 MDnsTransaction::SINGLE_RESULT
,
914 base::Bind(&MDnsTest::MockableRecordCallback
, base::Unretained(this)));
916 scoped_ptr
<MDnsTransaction
> transaction2
= test_client_
->CreateTransaction(
917 dns_protocol::kTypePTR
, "_printer._tcp.local",
918 MDnsTransaction::QUERY_CACHE
| MDnsTransaction::SINGLE_RESULT
,
919 base::Bind(&MDnsTest::MockableRecordCallback2
, base::Unretained(this)));
921 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD
,
925 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD
,
928 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2
.get(),
929 &MDnsTransaction::Start
)));
931 ASSERT_TRUE(transaction1
->Start());
933 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
936 TEST_F(MDnsTest
, GoodbyePacketNotification
) {
937 StrictMock
<MockListenerDelegate
> delegate_privet
;
939 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
940 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
941 ASSERT_TRUE(listener_privet
->Start());
943 SimulatePacketReceive(kSamplePacketGoodbye
, sizeof(kSamplePacketGoodbye
));
945 RunFor(base::TimeDelta::FromSeconds(2));
948 TEST_F(MDnsTest
, GoodbyePacketRemoval
) {
949 StrictMock
<MockListenerDelegate
> delegate_privet
;
951 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
952 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
953 ASSERT_TRUE(listener_privet
->Start());
955 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
958 SimulatePacketReceive(kSamplePacket2
, sizeof(kSamplePacket2
));
960 SimulatePacketReceive(kSamplePacketGoodbye
, sizeof(kSamplePacketGoodbye
));
962 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
965 RunFor(base::TimeDelta::FromSeconds(2));
968 // In order to reliably test reentrant listener deletes, we create two listeners
969 // and have each of them delete both, so we're guaranteed to try and deliver a
970 // callback to at least one deleted listener.
972 TEST_F(MDnsTest
, ListenerReentrantDelete
) {
973 StrictMock
<MockListenerDelegate
> delegate_privet
;
975 listener1_
= test_client_
->CreateListener(
976 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
978 listener2_
= test_client_
->CreateListener(
979 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet
);
981 ASSERT_TRUE(listener1_
->Start());
983 ASSERT_TRUE(listener2_
->Start());
985 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
987 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners
));
989 SimulatePacketReceive(kSamplePacket1
, sizeof(kSamplePacket1
));
991 EXPECT_EQ(NULL
, listener1_
.get());
992 EXPECT_EQ(NULL
, listener2_
.get());
995 ACTION_P(SaveIPAddress
, ip_container
) {
996 ::testing::StaticAssertTypeEq
<const RecordParsed
*, arg1_type
>();
997 ::testing::StaticAssertTypeEq
<IPAddressNumber
*, ip_container_type
>();
999 *ip_container
= arg1
->template rdata
<ARecordRdata
>()->address();
1002 TEST_F(MDnsTest
, DoubleRecordDisagreeing
) {
1003 IPAddressNumber address
;
1004 StrictMock
<MockListenerDelegate
> delegate_privet
;
1006 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1007 dns_protocol::kTypeA
, "privet.local", &delegate_privet
);
1009 ASSERT_TRUE(listener_privet
->Start());
1011 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
1013 .WillOnce(SaveIPAddress(&address
));
1015 SimulatePacketReceive(kCorruptedPacketDoubleRecord
,
1016 sizeof(kCorruptedPacketDoubleRecord
));
1018 EXPECT_EQ("2.3.4.5", IPAddressToString(address
));
1021 TEST_F(MDnsTest
, NsecWithListener
) {
1022 StrictMock
<MockListenerDelegate
> delegate_privet
;
1023 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1024 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1026 // Test to make sure nsec callback is NOT called for PTR
1027 // (which is marked as existing).
1028 StrictMock
<MockListenerDelegate
> delegate_privet2
;
1029 scoped_ptr
<MDnsListener
> listener_privet2
= test_client_
->CreateListener(
1030 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_privet2
);
1032 ASSERT_TRUE(listener_privet
->Start());
1034 EXPECT_CALL(delegate_privet
,
1035 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA
));
1037 SimulatePacketReceive(kSamplePacketNsec
,
1038 sizeof(kSamplePacketNsec
));
1041 TEST_F(MDnsTest
, NsecWithTransactionFromNetwork
) {
1042 scoped_ptr
<MDnsTransaction
> transaction_privet
=
1043 test_client_
->CreateTransaction(
1044 dns_protocol::kTypeA
, "_privet._tcp.local",
1045 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1046 MDnsTransaction::SINGLE_RESULT
,
1047 base::Bind(&MDnsTest::MockableRecordCallback
,
1048 base::Unretained(this)));
1050 EXPECT_CALL(socket_factory_
, OnSendTo(_
)).Times(2);
1052 ASSERT_TRUE(transaction_privet
->Start());
1055 MockableRecordCallback(MDnsTransaction::RESULT_NSEC
, NULL
));
1057 SimulatePacketReceive(kSamplePacketNsec
,
1058 sizeof(kSamplePacketNsec
));
1061 TEST_F(MDnsTest
, NsecWithTransactionFromCache
) {
1062 // Force mDNS to listen.
1063 StrictMock
<MockListenerDelegate
> delegate_irrelevant
;
1064 scoped_ptr
<MDnsListener
> listener_irrelevant
= test_client_
->CreateListener(
1065 dns_protocol::kTypePTR
, "_privet._tcp.local", &delegate_irrelevant
);
1066 listener_irrelevant
->Start();
1068 SimulatePacketReceive(kSamplePacketNsec
,
1069 sizeof(kSamplePacketNsec
));
1072 MockableRecordCallback(MDnsTransaction::RESULT_NSEC
, NULL
));
1074 scoped_ptr
<MDnsTransaction
> transaction_privet_a
=
1075 test_client_
->CreateTransaction(
1076 dns_protocol::kTypeA
, "_privet._tcp.local",
1077 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1078 MDnsTransaction::SINGLE_RESULT
,
1079 base::Bind(&MDnsTest::MockableRecordCallback
,
1080 base::Unretained(this)));
1082 ASSERT_TRUE(transaction_privet_a
->Start());
1084 // Test that a PTR transaction does NOT consider the same NSEC record to be a
1085 // valid answer to the query
1087 scoped_ptr
<MDnsTransaction
> transaction_privet_ptr
=
1088 test_client_
->CreateTransaction(
1089 dns_protocol::kTypePTR
, "_privet._tcp.local",
1090 MDnsTransaction::QUERY_NETWORK
| MDnsTransaction::QUERY_CACHE
|
1091 MDnsTransaction::SINGLE_RESULT
,
1092 base::Bind(&MDnsTest::MockableRecordCallback
,
1093 base::Unretained(this)));
1095 EXPECT_CALL(socket_factory_
, OnSendTo(_
)).Times(2);
1097 ASSERT_TRUE(transaction_privet_ptr
->Start());
1100 TEST_F(MDnsTest
, NsecConflictRemoval
) {
1101 StrictMock
<MockListenerDelegate
> delegate_privet
;
1102 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1103 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1105 ASSERT_TRUE(listener_privet
->Start());
1107 const RecordParsed
* record1
;
1108 const RecordParsed
* record2
;
1110 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
))
1111 .WillOnce(SaveArg
<1>(&record1
));
1113 SimulatePacketReceive(kSamplePacketAPrivet
,
1114 sizeof(kSamplePacketAPrivet
));
1116 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
))
1117 .WillOnce(SaveArg
<1>(&record2
));
1119 EXPECT_CALL(delegate_privet
,
1120 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA
));
1122 SimulatePacketReceive(kSamplePacketNsec
,
1123 sizeof(kSamplePacketNsec
));
1125 EXPECT_EQ(record1
, record2
);
1129 TEST_F(MDnsTest
, RefreshQuery
) {
1130 StrictMock
<MockListenerDelegate
> delegate_privet
;
1131 scoped_ptr
<MDnsListener
> listener_privet
= test_client_
->CreateListener(
1132 dns_protocol::kTypeA
, "_privet._tcp.local", &delegate_privet
);
1134 listener_privet
->SetActiveRefresh(true);
1135 ASSERT_TRUE(listener_privet
->Start());
1137 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_ADDED
, _
));
1139 SimulatePacketReceive(kSamplePacketAPrivet
,
1140 sizeof(kSamplePacketAPrivet
));
1142 // Expecting 2 calls (one for ipv4 and one for ipv6) for each of the 2
1143 // scheduled refresh queries.
1144 EXPECT_CALL(socket_factory_
, OnSendTo(
1145 MakeString(kQueryPacketPrivetA
, sizeof(kQueryPacketPrivetA
))))
1148 EXPECT_CALL(delegate_privet
, OnRecordUpdate(MDnsListener::RECORD_REMOVED
, _
));
1150 RunFor(base::TimeDelta::FromSeconds(6));
1153 // Note: These tests assume that the ipv4 socket will always be created first.
1154 // This is a simplifying assumption based on the way the code works now.
1155 class SimpleMockSocketFactory
: public MDnsSocketFactory
{
1157 void CreateSockets(ScopedVector
<DatagramServerSocket
>* sockets
) override
{
1159 sockets
->swap(sockets_
);
1162 void PushSocket(DatagramServerSocket
* socket
) {
1163 sockets_
.push_back(socket
);
1167 ScopedVector
<DatagramServerSocket
> sockets_
;
1170 class MockMDnsConnectionDelegate
: public MDnsConnection::Delegate
{
1172 virtual void HandlePacket(DnsResponse
* response
, int size
) {
1173 HandlePacketInternal(std::string(response
->io_buffer()->data(), size
));
1176 MOCK_METHOD1(HandlePacketInternal
, void(std::string packet
));
1178 MOCK_METHOD1(OnConnectionError
, void(int error
));
1181 class MDnsConnectionTest
: public ::testing::Test
{
1183 MDnsConnectionTest() : connection_(&delegate_
) {
1187 // Follow successful connection initialization.
1188 void SetUp() override
{
1189 socket_ipv4_
= new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4
);
1190 socket_ipv6_
= new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6
);
1191 factory_
.PushSocket(socket_ipv6_
);
1192 factory_
.PushSocket(socket_ipv4_
);
1193 sample_packet_
= MakeString(kSamplePacket1
, sizeof(kSamplePacket1
));
1194 sample_buffer_
= new StringIOBuffer(sample_packet_
);
1197 bool InitConnection() {
1198 return connection_
.Init(&factory_
);
1201 StrictMock
<MockMDnsConnectionDelegate
> delegate_
;
1203 MockMDnsDatagramServerSocket
* socket_ipv4_
;
1204 MockMDnsDatagramServerSocket
* socket_ipv6_
;
1205 SimpleMockSocketFactory factory_
;
1206 MDnsConnection connection_
;
1207 TestCompletionCallback callback_
;
1208 std::string sample_packet_
;
1209 scoped_refptr
<IOBuffer
> sample_buffer_
;
1212 TEST_F(MDnsConnectionTest
, ReceiveSynchronous
) {
1213 socket_ipv6_
->SetResponsePacket(sample_packet_
);
1214 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1215 .WillOnce(Return(ERR_IO_PENDING
));
1216 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1218 Invoke(socket_ipv6_
, &MockMDnsDatagramServerSocket::HandleRecvNow
))
1219 .WillOnce(Return(ERR_IO_PENDING
));
1221 EXPECT_CALL(delegate_
, HandlePacketInternal(sample_packet_
));
1222 ASSERT_TRUE(InitConnection());
1225 TEST_F(MDnsConnectionTest
, ReceiveAsynchronous
) {
1226 socket_ipv6_
->SetResponsePacket(sample_packet_
);
1228 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1229 .WillOnce(Return(ERR_IO_PENDING
));
1230 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1233 Invoke(socket_ipv6_
, &MockMDnsDatagramServerSocket::HandleRecvLater
))
1234 .WillOnce(Return(ERR_IO_PENDING
));
1236 ASSERT_TRUE(InitConnection());
1238 EXPECT_CALL(delegate_
, HandlePacketInternal(sample_packet_
));
1240 base::MessageLoop::current()->RunUntilIdle();
1243 TEST_F(MDnsConnectionTest
, Error
) {
1244 CompletionCallback callback
;
1246 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1247 .WillOnce(Return(ERR_IO_PENDING
));
1248 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1249 .WillOnce(DoAll(SaveArg
<3>(&callback
), Return(ERR_IO_PENDING
)));
1251 ASSERT_TRUE(InitConnection());
1253 EXPECT_CALL(delegate_
, OnConnectionError(ERR_SOCKET_NOT_CONNECTED
));
1254 callback
.Run(ERR_SOCKET_NOT_CONNECTED
);
1255 base::MessageLoop::current()->RunUntilIdle();
1258 class MDnsConnectionSendTest
: public MDnsConnectionTest
{
1260 void SetUp() override
{
1261 MDnsConnectionTest::SetUp();
1262 EXPECT_CALL(*socket_ipv4_
, RecvFrom(_
, _
, _
, _
))
1263 .WillOnce(Return(ERR_IO_PENDING
));
1264 EXPECT_CALL(*socket_ipv6_
, RecvFrom(_
, _
, _
, _
))
1265 .WillOnce(Return(ERR_IO_PENDING
));
1266 EXPECT_TRUE(InitConnection());
1270 TEST_F(MDnsConnectionSendTest
, Send
) {
1271 EXPECT_CALL(*socket_ipv4_
,
1272 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
));
1273 EXPECT_CALL(*socket_ipv6_
,
1274 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
));
1276 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1279 TEST_F(MDnsConnectionSendTest
, SendError
) {
1280 CompletionCallback callback
;
1282 EXPECT_CALL(*socket_ipv4_
,
1283 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
));
1284 EXPECT_CALL(*socket_ipv6_
,
1285 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1286 .WillOnce(DoAll(SaveArg
<2>(&callback
), Return(ERR_SOCKET_NOT_CONNECTED
)));
1288 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1289 EXPECT_CALL(delegate_
, OnConnectionError(ERR_SOCKET_NOT_CONNECTED
));
1290 base::MessageLoop::current()->RunUntilIdle();
1293 TEST_F(MDnsConnectionSendTest
, SendQueued
) {
1294 // Send data immediately.
1295 EXPECT_CALL(*socket_ipv4_
,
1296 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
))
1298 .WillRepeatedly(Return(OK
));
1300 CompletionCallback callback
;
1301 // Delay sending data. Only the first call should be made.
1302 EXPECT_CALL(*socket_ipv6_
,
1303 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1304 .WillOnce(DoAll(SaveArg
<2>(&callback
), Return(ERR_IO_PENDING
)));
1306 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1307 connection_
.Send(sample_buffer_
, sample_packet_
.size());
1309 // The second IPv6 packed is not sent yet.
1310 EXPECT_CALL(*socket_ipv4_
,
1311 SendToInternal(sample_packet_
, "224.0.0.251:5353", _
))
1313 // Expect call for the second IPv6 packed.
1314 EXPECT_CALL(*socket_ipv6_
,
1315 SendToInternal(sample_packet_
, "[ff02::fb]:5353", _
))
1316 .WillOnce(Return(OK
));