Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / dns / mdns_client_unittest.cc
blobbd84aca3d83469159640ac636e815731d19db322
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/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;
31 using ::testing::_;
33 namespace net {
35 namespace {
37 const uint8 kSamplePacket1[] = {
38 // Header
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
46 // Answer 1
47 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
48 0x04, '_', 't', 'c', 'p',
49 0x05, 'l', 'o', 'c', 'a', 'l',
50 0x00,
51 0x00, 0x0c, // TYPE is PTR.
52 0x00, 0x01, // CLASS is IN.
53 0x00, 0x00, // TTL (4 bytes) is 1 second;
54 0x00, 0x01,
55 0x00, 0x08, // RDLENGTH is 8 bytes.
56 0x05, 'h', 'e', 'l', 'l', 'o',
57 0xc0, 0x0c,
59 // Answer 2
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.
65 0x24, 0x75,
66 0x00, 0x08, // RDLENGTH is 8 bytes.
67 0x05, 'h', 'e', 'l', 'l', 'o',
68 0xc0, 0x32
71 const uint8 kCorruptedPacketBadQuestion[] = {
72 // Header
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',
82 0x00,
83 0x00, 0x00,
84 0x00, 0x00,
86 // Answer 1
87 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
88 0x04, '_', 't', 'c', 'p',
89 0x05, 'l', 'o', 'c', 'a', 'l',
90 0x00,
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.
94 0x24, 0x74,
95 0x00, 0x99, // RDLENGTH is impossible
96 0x05, 'h', 'e', 'l', 'l', 'o',
97 0xc0, 0x0c,
99 // Answer 2
100 0x08, '_', 'p', 'r', // Useless trailing data.
103 const uint8 kCorruptedPacketUnsalvagable[] = {
104 // Header
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
112 // Answer 1
113 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
114 0x04, '_', 't', 'c', 'p',
115 0x05, 'l', 'o', 'c', 'a', 'l',
116 0x00,
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.
120 0x24, 0x74,
121 0x00, 0x99, // RDLENGTH is impossible
122 0x05, 'h', 'e', 'l', 'l', 'o',
123 0xc0, 0x0c,
125 // Answer 2
126 0x08, '_', 'p', 'r', // Useless trailing data.
129 const uint8 kCorruptedPacketDoubleRecord[] = {
130 // Header
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
138 // Answer 1
139 0x06, 'p', 'r', 'i', 'v', 'e', 't',
140 0x05, 'l', 'o', 'c', 'a', 'l',
141 0x00,
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.
145 0x24, 0x74,
146 0x00, 0x04, // RDLENGTH is 4
147 0x05, 0x03,
148 0xc0, 0x0c,
150 // Answer 2 -- Same key
151 0x06, 'p', 'r', 'i', 'v', 'e', 't',
152 0x05, 'l', 'o', 'c', 'a', 'l',
153 0x00,
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.
157 0x24, 0x74,
158 0x00, 0x04, // RDLENGTH is 4
159 0x02, 0x03,
160 0x04, 0x05,
163 const uint8 kCorruptedPacketSalvagable[] = {
164 // Header
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
172 // Answer 1
173 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
174 0x04, '_', 't', 'c', 'p',
175 0x05, 'l', 'o', 'c', 'a', 'l',
176 0x00,
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.
180 0x24, 0x74,
181 0x00, 0x08, // RDLENGTH is 8 bytes.
182 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
183 0xc0, 0x0c,
185 // Answer 2
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.
191 0x24, 0x75,
192 0x00, 0x08, // RDLENGTH is 8 bytes.
193 0x05, 'h', 'e', 'l', 'l', 'o',
194 0xc0, 0x32
197 const uint8 kSamplePacket2[] = {
198 // Header
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
206 // Answer 1
207 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
208 0x04, '_', 't', 'c', 'p',
209 0x05, 'l', 'o', 'c', 'a', 'l',
210 0x00,
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.
214 0x24, 0x74,
215 0x00, 0x08, // RDLENGTH is 8 bytes.
216 0x05, 'z', 'z', 'z', 'z', 'z',
217 0xc0, 0x0c,
219 // Answer 2
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.
225 0x24, 0x74,
226 0x00, 0x08, // RDLENGTH is 8 bytes.
227 0x05, 'z', 'z', 'z', 'z', 'z',
228 0xc0, 0x32
231 const uint8 kSamplePacket3[] = {
232 // Header
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
240 // Answer 1
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;
247 0x00, 0x01, //
248 0x00, 0x08, // RDLENGTH is 8 bytes.
249 0x05, 'h', 'e', 'l', 'l', 'o', //
250 0xc0, 0x0c, //
252 // Answer 2
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.
258 0x00, 0x03, //
259 0x00, 0x08, // RDLENGTH is 8 bytes.
260 0x05, 'h', 'e', 'l', 'l', 'o', //
261 0xc0, 0x32};
263 const uint8 kQueryPacketPrivet[] = {
264 // Header
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
272 // Question
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',
277 0x00,
278 0x00, 0x0c, // TYPE is PTR.
279 0x00, 0x01, // CLASS is IN.
282 const uint8 kQueryPacketPrivetA[] = {
283 // Header
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
291 // Question
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',
296 0x00,
297 0x00, 0x01, // TYPE is A.
298 0x00, 0x01, // CLASS is IN.
301 const uint8 kSamplePacketAdditionalOnly[] = {
302 // Header
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
310 // Answer 1
311 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
312 0x04, '_', 't', 'c', 'p',
313 0x05, 'l', 'o', 'c', 'a', 'l',
314 0x00,
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.
318 0x24, 0x74,
319 0x00, 0x08, // RDLENGTH is 8 bytes.
320 0x05, 'h', 'e', 'l', 'l', 'o',
321 0xc0, 0x0c,
324 const uint8 kSamplePacketNsec[] = {
325 // Header
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
333 // Answer 1
334 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
335 0x04, '_', 't', 'c', 'p',
336 0x05, 'l', 'o', 'c', 'a', 'l',
337 0x00,
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.
341 0x24, 0x74,
342 0x00, 0x06, // RDLENGTH is 6 bytes.
343 0xc0, 0x0c,
344 0x00, 0x02, 0x00, 0x08 // Only A record present
347 const uint8 kSamplePacketAPrivet[] = {
348 // Header
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
356 // Answer 1
357 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
358 0x04, '_', 't', 'c', 'p',
359 0x05, 'l', 'o', 'c', 'a', 'l',
360 0x00,
361 0x00, 0x01, // TYPE is A.
362 0x00, 0x01, // CLASS is IN.
363 0x00, 0x00, // TTL (4 bytes) is 5 seconds
364 0x00, 0x05,
365 0x00, 0x04, // RDLENGTH is 4 bytes.
366 0xc0, 0x0c,
367 0x00, 0x02,
370 const uint8 kSamplePacketGoodbye[] = {
371 // Header
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
379 // Answer 1
380 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
381 0x04, '_', 't', 'c', 'p',
382 0x05, 'l', 'o', 'c', 'a', 'l',
383 0x00,
384 0x00, 0x0c, // TYPE is PTR.
385 0x00, 0x01, // CLASS is IN.
386 0x00, 0x00, // TTL (4 bytes) is zero;
387 0x00, 0x00,
388 0x00, 0x08, // RDLENGTH is 8 bytes.
389 0x05, 'z', 'z', 'z', 'z', 'z',
390 0xc0, 0x0c,
393 std::string MakeString(const uint8* data, unsigned size) {
394 return std::string(reinterpret_cast<const char*>(data), size);
397 class PtrRecordCopyContainer {
398 public:
399 PtrRecordCopyContainer() {}
400 ~PtrRecordCopyContainer() {}
402 bool is_set() const { return set_; }
404 void SaveWithDummyArg(int unused, const RecordParsed* value) {
405 Save(value);
408 void Save(const RecordParsed* value) {
409 set_ = true;
410 name_ = value->name();
411 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
412 ttl_ = value->ttl();
415 bool IsRecordWith(const std::string& name, const 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_; }
423 private:
424 bool set_;
425 std::string name_;
426 std::string ptrdomain_;
427 int ttl_;
430 class MockClock : public base::DefaultClock {
431 public:
432 MockClock() : base::DefaultClock() {}
433 virtual ~MockClock() {}
435 MOCK_METHOD0(Now, base::Time());
437 private:
438 DISALLOW_COPY_AND_ASSIGN(MockClock);
441 class MockTimer : public base::MockTimer {
442 public:
443 MockTimer() : base::MockTimer(false, false) {}
444 ~MockTimer() {}
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));
460 private:
461 DISALLOW_COPY_AND_ASSIGN(MockTimer);
464 } // namespace
466 class MDnsTest : public ::testing::Test {
467 public:
468 void SetUp() override;
469 void DeleteTransaction();
470 void DeleteBothListeners();
471 void RunFor(base::TimeDelta time_period);
472 void Stop();
474 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
475 const RecordParsed* record));
477 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
478 const RecordParsed* record));
480 protected:
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
489 // reentrancy tests.
490 scoped_ptr<MDnsTransaction> transaction_;
491 scoped_ptr<MDnsListener> listener1_;
492 scoped_ptr<MDnsListener> listener2_;
495 class MockListenerDelegate : public MDnsListener::Delegate {
496 public:
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)))
515 .Times(2);
518 void MDnsTest::DeleteTransaction() {
519 transaction_.reset();
522 void MDnsTest::DeleteBothListeners() {
523 listener1_.reset();
524 listener2_.reset();
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();
534 callback.Cancel();
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, _))
559 .Times(Exactly(1))
560 .WillOnce(Invoke(
561 &record_privet,
562 &PtrRecordCopyContainer::SaveWithDummyArg));
564 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
565 .Times(Exactly(1))
566 .WillOnce(Invoke(
567 &record_printer,
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, _))
596 .Times(Exactly(1))
597 .WillOnce(Invoke(
598 &record_privet,
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, _))
608 .Times(Exactly(1))
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;
629 test_client_.reset(
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())
635 .Times(3)
636 .WillRepeatedly(Return(start_time))
637 .RetiresOnSaturation();
639 // Receive two records with different TTL values.
640 // TTL(privet)=1.0s
641 // TTL(printer)=3.0s
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, _))
657 .Times(Exactly(1));
658 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
659 .Times(Exactly(1));
661 SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
663 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
664 .Times(Exactly(1));
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(), _));
678 timer->Fire();
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, _))
692 .Times(Exactly(1))
693 .WillOnce(Invoke(
694 &record_printer,
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, _))
729 .Times(Exactly(1))
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)));
747 EXPECT_CALL(*this,
748 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
749 .Times(Exactly(1));
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, _))
796 .Times(Exactly(1))
797 .WillOnce(Invoke(
798 &record_privet,
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());
821 EXPECT_CALL(*this,
822 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
823 .Times(Exactly(1))
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, _))
845 .Times(Exactly(2))
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,
878 NULL))
879 .Times(Exactly(1))
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, _))
902 .Times(Exactly(1))
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,
926 .Times(Exactly(1));
928 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD,
930 .Times(Exactly(1))
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, _))
959 .Times(Exactly(1));
961 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
963 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye));
965 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
966 .Times(Exactly(1));
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, _))
989 .Times(Exactly(1))
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, _))
1015 .Times(Exactly(1))
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());
1057 EXPECT_CALL(*this,
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));
1074 EXPECT_CALL(*this,
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))))
1149 .Times(4);
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 {
1159 public:
1160 void CreateSockets(ScopedVector<DatagramServerSocket>* sockets) override {
1161 sockets->clear();
1162 sockets->swap(sockets_);
1165 void PushSocket(DatagramServerSocket* socket) {
1166 sockets_.push_back(socket);
1169 private:
1170 ScopedVector<DatagramServerSocket> sockets_;
1173 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
1174 public:
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 {
1185 public:
1186 MDnsConnectionTest() : connection_(&delegate_) {
1189 protected:
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(_, _, _, _))
1220 .WillOnce(
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(_, _, _, _))
1234 .Times(2)
1235 .WillOnce(
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 {
1262 protected:
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", _))
1300 .Times(2)
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", _))
1315 .Times(0);
1316 // Expect call for the second IPv6 packed.
1317 EXPECT_CALL(*socket_ipv6_,
1318 SendToInternal(sample_packet_, "[ff02::fb]:5353", _))
1319 .WillOnce(Return(OK));
1320 callback.Run(OK);
1323 } // namespace net