Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: net/dns/mdns_client_unittest.cc

Issue 15733008: Multicast DNS implementation (initial) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mdns_implementation2
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <queue>
6
7 #include "base/memory/ref_counted.h"
8 #include "base/message_loop.h"
9 #include "net/base/rand_callback.h"
10 #include "net/base/test_completion_callback.h"
11 #include "net/dns/mdns_client_impl.h"
12 #include "net/dns/record_rdata.h"
13 #include "net/udp/udp_client_socket.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using ::testing::Invoke;
18 using ::testing::InvokeWithoutArgs;
19 using ::testing::StrictMock;
20 using ::testing::NiceMock;
21 using ::testing::Exactly;
22 using ::testing::Return;
23 using ::testing::SaveArg;
24 using ::testing::_;
25
26 namespace net {
27
28 namespace {
29
30 const char kSamplePacket1[] = {
31 // Header
32 0x00, 0x00, // ID is zeroed out
33 0x81, 0x80, // Standard query response, RA, no error
34 0x00, 0x00, // No questions (for simplicity)
35 0x00, 0x02, // 2 RRs (answers)
36 0x00, 0x00, // 0 authority RRs
37 0x00, 0x00, // 0 additional RRs
38
39 // Answer 1
40 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
41 0x04, '_', 't', 'c', 'p',
42 0x05, 'l', 'o', 'c', 'a', 'l',
43 0x00,
44 0x00, 0x0c, // TYPE is PTR.
45 0x00, 0x01, // CLASS is IN.
46 0x00, 0x00, // TTL (4 bytes) is 1 second;
47 0x00, 0x01,
48 0x00, 0x08, // RDLENGTH is 8 bytes.
49 0x05, 'h', 'e', 'l', 'l', 'o',
50 0xc0, 0x0c,
51
52 // Answer 2
53 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
54 0xc0, 0x14, // Pointer to "._tcp.local"
55 0x00, 0x0c, // TYPE is PTR.
56 0x00, 0x01, // CLASS is IN.
57 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
58 0x24, 0x75,
59 0x00, 0x08, // RDLENGTH is 8 bytes.
60 0x05, 'h', 'e', 'l', 'l', 'o',
61 0xc0, 0x32
62 };
63
64 const char kCorruptedPacketBadQuestion[] = {
65 // Header
66 0x00, 0x00, // ID is zeroed out
67 0x81, 0x80, // Standard query response, RA, no error
68 0x00, 0x01, // One question
69 0x00, 0x02, // 2 RRs (answers)
70 0x00, 0x00, // 0 authority RRs
71 0x00, 0x00, // 0 additional RRs
72
73 // Question is corrupted and cannot be read.
74 0x99, 'h', 'e', 'l', 'l', 'o',
75 0x00,
76 0x00, 0x00,
77 0x00, 0x00,
78
79 // Answer 1
80 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
81 0x04, '_', 't', 'c', 'p',
82 0x05, 'l', 'o', 'c', 'a', 'l',
83 0x00,
84 0x00, 0x0c, // TYPE is PTR.
85 0x00, 0x01, // CLASS is IN.
86 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
87 0x24, 0x74,
88 0x00, 0x99, // RDLENGTH is impossible
89 0x05, 'h', 'e', 'l', 'l', 'o',
90 0xc0, 0x0c,
91
92 // Answer 2
93 0x08, '_', 'p', 'r', // Useless trailing data.
94 };
95
96 const char kCorruptedPacketUnsalvagable[] = {
97 // Header
98 0x00, 0x00, // ID is zeroed out
99 0x81, 0x80, // Standard query response, RA, no error
100 0x00, 0x00, // No questions (for simplicity)
101 0x00, 0x02, // 2 RRs (answers)
102 0x00, 0x00, // 0 authority RRs
103 0x00, 0x00, // 0 additional RRs
104
105 // Answer 1
106 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
107 0x04, '_', 't', 'c', 'p',
108 0x05, 'l', 'o', 'c', 'a', 'l',
109 0x00,
110 0x00, 0x0c, // TYPE is PTR.
111 0x00, 0x01, // CLASS is IN.
112 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
113 0x24, 0x74,
114 0x00, 0x99, // RDLENGTH is impossible
115 0x05, 'h', 'e', 'l', 'l', 'o',
116 0xc0, 0x0c,
117
118 // Answer 2
119 0x08, '_', 'p', 'r', // Useless trailing data.
120 };
121
122 const char kCorruptedPacketSalvagable[] = {
123 // Header
124 0x00, 0x00, // ID is zeroed out
125 0x81, 0x80, // Standard query response, RA, no error
126 0x00, 0x00, // No questions (for simplicity)
127 0x00, 0x02, // 2 RRs (answers)
128 0x00, 0x00, // 0 authority RRs
129 0x00, 0x00, // 0 additional RRs
130
131 // Answer 1
132 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
133 0x04, '_', 't', 'c', 'p',
134 0x05, 'l', 'o', 'c', 'a', 'l',
135 0x00,
136 0x00, 0x0c, // TYPE is PTR.
137 0x00, 0x01, // CLASS is IN.
138 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
139 0x24, 0x74,
140 0x00, 0x08, // RDLENGTH is 8 bytes.
141 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format.
142 0xc0, 0x0c,
143
144 // Answer 2
145 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
146 0xc0, 0x14, // Pointer to "._tcp.local"
147 0x00, 0x0c, // TYPE is PTR.
148 0x00, 0x01, // CLASS is IN.
149 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds.
150 0x24, 0x75,
151 0x00, 0x08, // RDLENGTH is 8 bytes.
152 0x05, 'h', 'e', 'l', 'l', 'o',
153 0xc0, 0x32
154 };
155
156 const char kSamplePacket2[] = {
157 // Header
158 0x00, 0x00, // ID is zeroed out
159 0x81, 0x80, // Standard query response, RA, no error
160 0x00, 0x00, // No questions (for simplicity)
161 0x00, 0x02, // 2 RRs (answers)
162 0x00, 0x00, // 0 authority RRs
163 0x00, 0x00, // 0 additional RRs
164
165 // Answer 1
166 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
167 0x04, '_', 't', 'c', 'p',
168 0x05, 'l', 'o', 'c', 'a', 'l',
169 0x00,
170 0x00, 0x0c, // TYPE is PTR.
171 0x00, 0x01, // CLASS is IN.
172 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
173 0x24, 0x74,
174 0x00, 0x08, // RDLENGTH is 8 bytes.
175 0x05, 'z', 'z', 'z', 'z', 'z',
176 0xc0, 0x0c,
177
178 // Answer 2
179 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r',
180 0xc0, 0x14, // Pointer to "._tcp.local"
181 0x00, 0x0c, // TYPE is PTR.
182 0x00, 0x01, // CLASS is IN.
183 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
184 0x24, 0x74,
185 0x00, 0x08, // RDLENGTH is 8 bytes.
186 0x05, 'z', 'z', 'z', 'z', 'z',
187 0xc0, 0x32
188 };
189
190 const char kQueryPacketPrivet[] = {
191 // Header
192 0x00, 0x00, // ID is zeroed out
193 0x00, 0x00, // No flags.
194 0x00, 0x01, // One question.
195 0x00, 0x00, // 0 RRs (answers)
196 0x00, 0x00, // 0 authority RRs
197 0x00, 0x00, // 0 additional RRs
198
199 // Question
200 // This part is echoed back from the respective query.
201 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
202 0x04, '_', 't', 'c', 'p',
203 0x05, 'l', 'o', 'c', 'a', 'l',
204 0x00,
205 0x00, 0x0c, // TYPE is PTR.
206 0x00, 0x01, // CLASS is IN.
207 };
208
209 const char kSamplePacketAdditionalOnly[] = {
210 // Header
211 0x00, 0x00, // ID is zeroed out
212 0x81, 0x80, // Standard query response, RA, no error
213 0x00, 0x00, // No questions (for simplicity)
214 0x00, 0x00, // 2 RRs (answers)
215 0x00, 0x00, // 0 authority RRs
216 0x00, 0x01, // 0 additional RRs
217
218 // Answer 1
219 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
220 0x04, '_', 't', 'c', 'p',
221 0x05, 'l', 'o', 'c', 'a', 'l',
222 0x00,
223 0x00, 0x0c, // TYPE is PTR.
224 0x00, 0x01, // CLASS is IN.
225 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
226 0x24, 0x74,
227 0x00, 0x08, // RDLENGTH is 8 bytes.
228 0x05, 'h', 'e', 'l', 'l', 'o',
229 0xc0, 0x0c,
230 };
231
232 class MockDatagramServerSocket : public DatagramServerSocket {
233 public:
234 // DatagramServerSocket implementation:
235 int Listen(const IPEndPoint& address) {
236 return ListenInternal(address.ToString());
237 }
238
239 MOCK_METHOD1(ListenInternal, int(const std::string& address));
240
241 MOCK_METHOD4(RecvFrom, int(IOBuffer* buffer, int size,
242 IPEndPoint* address,
243 const CompletionCallback& callback));
244
245 int SendTo(IOBuffer* buf, int buf_len, const IPEndPoint& address,
246 const CompletionCallback& callback) {
247 return SendToInternal(std::string(buf->data(), buf_len), address.ToString(),
248 callback);
249 }
250
251 MOCK_METHOD3(SendToInternal, int(const std::string& packet,
252 const std::string address,
253 const CompletionCallback& callback));
254
255 MOCK_METHOD1(SetReceiveBufferSize, bool(int32 size));
256 MOCK_METHOD1(SetSendBufferSize, bool(int32 size));
257
258 MOCK_METHOD0(Close, void());
259
260 MOCK_CONST_METHOD1(GetPeerAddress, int(IPEndPoint* address));
261 MOCK_CONST_METHOD1(GetLocalAddress, int(IPEndPoint* address));
262 MOCK_CONST_METHOD0(NetLog, const BoundNetLog&());
263
264 MOCK_METHOD0(AllowAddressReuse, void());
265 MOCK_METHOD0(AllowBroadcast, void());
266
267 int JoinGroup(const IPAddressNumber& group_address) const {
268 return JoinGroupInternal(IPAddressToString(group_address));
269 }
270
271 MOCK_CONST_METHOD1(JoinGroupInternal, int(const std::string& group));
272
273 int LeaveGroup(const IPAddressNumber& group_address) const {
274 return LeaveGroupInternal(IPAddressToString(group_address));
275 }
276
277 MOCK_CONST_METHOD1(LeaveGroupInternal, int(const std::string& group));
278
279 MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
280
281 MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
282
283 void SetResponsePacket(std::string response_packet) {
284 response_packet_ = response_packet;
285 }
286
287 int HandleRecvNow(IOBuffer* buffer, int size, IPEndPoint* address,
288 const CompletionCallback& callback) {
289 int size_returned =
290 std::min(response_packet_.size(), static_cast<size_t>(size));
291 memcpy(buffer->data(), response_packet_.data(), size_returned);
292 return size_returned;
293 }
294
295 int HandleRecvLater(IOBuffer* buffer, int size, IPEndPoint* address,
296 const CompletionCallback& callback) {
297 int rv = HandleRecvNow(buffer, size, address, callback);
298 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, rv));
299 return ERR_IO_PENDING;
300 }
301
302 private:
303 std::string response_packet_;
304 };
305
306 class MockSocketFactory
307 : public MDnsConnection::SocketFactory {
308 public:
309 MockSocketFactory() {
310 }
311
312 virtual ~MockSocketFactory() {
313 }
314
315 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
316 scoped_ptr<MockDatagramServerSocket> new_socket(
317 new NiceMock<MockDatagramServerSocket>);
318
319 ON_CALL(*new_socket, SendToInternal(_, _, _))
320 .WillByDefault(Invoke(
321 this,
322 &MockSocketFactory::SendToInternal));
323
324 ON_CALL(*new_socket, RecvFrom(_, _, _, _))
325 .WillByDefault(Invoke(
326 this,
327 &MockSocketFactory::RecvFromInternal));
328
329 return new_socket.PassAs<DatagramServerSocket>();
330 }
331
332 void SimulateReceive(const char* packet, int size) {
333 DCHECK(recv_buffer_size_ >= size);
334 DCHECK(recv_buffer_.get());
335 DCHECK(!recv_callback_.is_null());
336
337 memcpy(recv_buffer_->data(), packet, size);
338 CompletionCallback recv_callback = recv_callback_;
339 recv_callback_.Reset();
340 recv_callback.Run(size);
341 }
342
343 MOCK_METHOD1(OnSendTo, void(const std::string&));
344
345 private:
346 int SendToInternal(const std::string& packet, const std::string& address,
347 const CompletionCallback& callback) {
348 OnSendTo(packet);
349 return packet.size();
350 }
351
352 // The latest receive callback is always saved, since the MDnsConnection
353 // does not care which socket a packet is received on.
354 int RecvFromInternal(IOBuffer* buffer, int size,
355 IPEndPoint* address,
356 const CompletionCallback& callback) {
357 recv_buffer_ = buffer;
358 recv_buffer_size_ = size;
359 recv_callback_ = callback;
360 return ERR_IO_PENDING;
361 }
362
363 scoped_refptr<IOBuffer> recv_buffer_;
364 int recv_buffer_size_;
365 CompletionCallback recv_callback_;
366 };
367
368 class PtrRecordCopyContainer {
369 public:
370 PtrRecordCopyContainer() {}
371 ~PtrRecordCopyContainer() {}
372
373 bool is_set() const { return set_; }
374
375 void SaveWithDummyArg(int unused, const RecordParsed* value) {
376 Save(value);
377 }
378
379 void Save(const RecordParsed* value) {
380 set_ = true;
381 name_ = value->name();
382 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
383 ttl_ = value->ttl();
384 }
385
386 bool IsRecordWith(std::string name, std::string ptrdomain) {
387 return set_ && name_ == name && ptrdomain_ == ptrdomain;
388 }
389
390 const std::string& name() { return name_; }
391 const std::string& ptrdomain() { return ptrdomain_; }
392 int ttl() { return ttl_; }
393
394 private:
395 bool set_;
396 std::string name_;
397 std::string ptrdomain_;
398 int ttl_;
399 };
400
401 class MDnsTest : public ::testing::Test {
402 public:
403 MDnsTest();
404 virtual ~MDnsTest();
405 void DeleteTransaction();
406 void DeleteBothListeners();
407 void RunUntilIdle();
408 void RunFor(base::TimeDelta time_period);
409 void Stop();
410
411 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result,
412 const RecordParsed* record));
413
414 protected:
415 void ExpectPacket(const char* packet, unsigned size);
416 void SimulatePacketReceive(const char* packet, unsigned size);
417
418 base::MessageLoop* message_loop_;
419
420 scoped_ptr<MDnsClientImpl> test_client_;
421 IPEndPoint mdns_ipv4_endpoint_;
422 StrictMock<MockSocketFactory>* socket_factory_;
423
424 // Transactions and listeners that can be deleted by class methods for
425 // reentrancy tests.
426 scoped_ptr<MDnsTransaction> transaction_;
427 scoped_ptr<MDnsListener> listener1_;
428 scoped_ptr<MDnsListener> listener2_;
429 };
430
431 class MockListenerDelegate : public MDnsListener::Delegate {
432 public:
433 MOCK_METHOD2(OnRecordUpdate,
434 void(MDnsListener::UpdateType update,
435 const RecordParsed* records));
436 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
437 MOCK_METHOD0(OnCachePurged, void());
438 };
439
440 MDnsTest::MDnsTest()
441 : message_loop_(base::MessageLoop::current()) {
442 socket_factory_ = new StrictMock<MockSocketFactory>();
443 test_client_.reset(new MDnsClientImpl(
444 scoped_ptr<MDnsConnection::SocketFactory>(socket_factory_)));
445 }
446
447 MDnsTest::~MDnsTest() {
448 }
449
450 void MDnsTest::SimulatePacketReceive(const char* packet, unsigned size) {
451 socket_factory_->SimulateReceive(packet, size);
452 }
453
454 void MDnsTest::ExpectPacket(
455 const char* packet,
456 unsigned size) {
457 EXPECT_CALL(*socket_factory_, OnSendTo(std::string(packet, size)))
458 .Times(2);
459 }
460
461 void MDnsTest::DeleteTransaction() {
462 transaction_.reset();
463 }
464
465 void MDnsTest::DeleteBothListeners() {
466 listener1_.reset();
467 listener2_.reset();
468 }
469
470 void MDnsTest::RunUntilIdle() {
471 base::MessageLoop::current()->RunUntilIdle();
472 }
473
474 void MDnsTest::RunFor(base::TimeDelta time_period) {
475 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
476 base::Unretained(this)));
477 base::MessageLoop::current()->PostDelayedTask(
478 FROM_HERE, callback.callback(), time_period);
479
480 base::MessageLoop::current()->Run();
481 callback.Cancel();
482 }
483
484 void MDnsTest::Stop() {
485 base::MessageLoop::current()->Quit();
486 }
487
488 TEST_F(MDnsTest, PassiveListeners) {
489 StrictMock<MockListenerDelegate> delegate_privet;
490 StrictMock<MockListenerDelegate> delegate_printer;
491 StrictMock<MockListenerDelegate> delegate_ptr;
492
493 PtrRecordCopyContainer record_privet;
494 PtrRecordCopyContainer record_printer;
495
496 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
497 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
498 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
499 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
500 scoped_ptr<MDnsListener> listener_ptr = test_client_->CreateListener(
501 dns_protocol::kTypePTR, "", &delegate_ptr);
502
503 ASSERT_TRUE(listener_privet->Start());
504 ASSERT_TRUE(listener_printer->Start());
505 ASSERT_TRUE(listener_ptr->Start());
506
507 ASSERT_TRUE(test_client_->IsListeningForTests());
508
509 // Send the same packet twice to ensure no records are double-counted.
510
511 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
512 .Times(Exactly(1))
513 .WillOnce(Invoke(
514 &record_privet,
515 &PtrRecordCopyContainer::SaveWithDummyArg));
516
517 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
518 .Times(Exactly(1))
519 .WillOnce(Invoke(
520 &record_printer,
521 &PtrRecordCopyContainer::SaveWithDummyArg));
522
523 EXPECT_CALL(delegate_ptr, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
524 .Times(Exactly(2));
525
526 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
527 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
528
529 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
530 "hello._privet._tcp.local"));
531
532 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
533 "hello._printer._tcp.local"));
534
535 listener_privet.reset();
536 listener_printer.reset();
537
538 ASSERT_TRUE(test_client_->IsListeningForTests());
539
540 EXPECT_CALL(delegate_ptr, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
541 .Times(Exactly(2));
542
543 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
544
545 // Test to make sure mdns listener is not active with no listeners present.
546 listener_ptr.reset();
547
548 RunUntilIdle();
549
550 ASSERT_FALSE(test_client_->IsListeningForTests());
551 }
552
553 TEST_F(MDnsTest, PassiveListenersCacheCleanup) {
554 StrictMock<MockListenerDelegate> delegate_privet;
555
556 PtrRecordCopyContainer record_privet;
557 PtrRecordCopyContainer record_privet2;
558
559 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
560 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
561
562 ASSERT_TRUE(listener_privet->Start());
563
564 ASSERT_TRUE(test_client_->IsListeningForTests());
565
566 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
567 .Times(Exactly(1))
568 .WillOnce(Invoke(
569 &record_privet,
570 &PtrRecordCopyContainer::SaveWithDummyArg));
571
572 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
573
574 RunUntilIdle();
szym 2013/06/13 19:20:00 I don't think you need any RunUntilIdle after just
575
576 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
577 "hello._privet._tcp.local"));
578
579 // Expect record is removed when its TTL expires.
580 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
581 .Times(Exactly(1))
582 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
583 Invoke(&record_privet2,
584 &PtrRecordCopyContainer::SaveWithDummyArg)));
585
586 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
587
588 RunUntilIdle();
589
590 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
591 "hello._privet._tcp.local"));
592 }
593
594 TEST_F(MDnsTest, MalformedPacket) {
595 StrictMock<MockListenerDelegate> delegate_printer;
596
597 PtrRecordCopyContainer record_printer;
598
599 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
600 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
601
602 ASSERT_TRUE(listener_printer->Start());
603
604 ASSERT_TRUE(test_client_->IsListeningForTests());
605
606 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
607 .Times(Exactly(1))
608 .WillOnce(Invoke(
609 &record_printer,
610 &PtrRecordCopyContainer::SaveWithDummyArg));
611
612 // First, send unsalvagable packet to ensure we can deal with it.
613 SimulatePacketReceive(kCorruptedPacketUnsalvagable,
614 sizeof(kCorruptedPacketUnsalvagable));
615
616 // Regression test: send a packet where the question cannot be read.
617 SimulatePacketReceive(kCorruptedPacketBadQuestion,
618 sizeof(kCorruptedPacketBadQuestion));
619
620 // Then send salvagable packet to ensure we can extract useful records.
621 SimulatePacketReceive(kCorruptedPacketSalvagable,
622 sizeof(kCorruptedPacketSalvagable));
623
624 RunUntilIdle();
625
626 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
627 "hello._printer._tcp.local"));
628 }
629
630 TEST_F(MDnsTest, TransactionWithEmptyCache) {
631 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
632
633 scoped_ptr<MDnsTransaction> transaction_privet =
634 test_client_->CreateTransaction(
635 dns_protocol::kTypePTR, "_privet._tcp.local",
636 MDnsTransaction::QUERY_NETWORK |
637 MDnsTransaction::QUERY_CACHE |
638 MDnsTransaction::SINGLE_RESULT,
639 base::Bind(&MDnsTest::MockableRecordCallback,
640 base::Unretained(this)));
641
642 ASSERT_TRUE(transaction_privet->Start());
643
644 EXPECT_TRUE(test_client_->IsListeningForTests());
645
646 PtrRecordCopyContainer record_privet;
647
648 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
649 .Times(Exactly(1))
650 .WillOnce(Invoke(&record_privet,
651 &PtrRecordCopyContainer::SaveWithDummyArg));
652
653 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
654
655 RunUntilIdle();
656
657 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
658 "hello._privet._tcp.local"));
659
660 EXPECT_FALSE(test_client_->IsListeningForTests());
661 }
662
663 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
664 scoped_ptr<MDnsTransaction> transaction_privet =
665 test_client_->CreateTransaction(
666 dns_protocol::kTypePTR, "_privet._tcp.local",
667 MDnsTransaction::QUERY_CACHE |
668 MDnsTransaction::SINGLE_RESULT,
669 base::Bind(&MDnsTest::MockableRecordCallback,
670 base::Unretained(this)));
671
672 EXPECT_CALL(*this,
673 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _))
674 .Times(Exactly(1));
675
676 ASSERT_TRUE(transaction_privet->Start());
677
678 EXPECT_FALSE(test_client_->IsListeningForTests());
679
680 RunUntilIdle();
681 }
682
683 TEST_F(MDnsTest, TransactionWithCache) {
684 // Listener to force the client to listen
685 StrictMock<MockListenerDelegate> delegate_irrelevant;
686 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
687 dns_protocol::kTypeA, "codereview.chromium.local",
688 &delegate_irrelevant);
689
690 ASSERT_TRUE(listener_irrelevant->Start());
691
692 EXPECT_TRUE(test_client_->IsListeningForTests());
693
694 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
695
696 RunUntilIdle();
697
698 PtrRecordCopyContainer record_privet;
699
700 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
701 .WillOnce(Invoke(&record_privet,
702 &PtrRecordCopyContainer::SaveWithDummyArg));
703
704 scoped_ptr<MDnsTransaction> transaction_privet =
705 test_client_->CreateTransaction(
706 dns_protocol::kTypePTR, "_privet._tcp.local",
707 MDnsTransaction::QUERY_NETWORK |
708 MDnsTransaction::QUERY_CACHE |
709 MDnsTransaction::SINGLE_RESULT,
710 base::Bind(&MDnsTest::MockableRecordCallback,
711 base::Unretained(this)));
712
713 ASSERT_TRUE(transaction_privet->Start());
714
715 RunUntilIdle();
716
717 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
718 "hello._privet._tcp.local"));
719 }
720
721 TEST_F(MDnsTest, AdditionalRecords) {
722 StrictMock<MockListenerDelegate> delegate_privet;
723
724 PtrRecordCopyContainer record_privet;
725
726 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
727 dns_protocol::kTypePTR, "_privet._tcp.local",
728 &delegate_privet);
729
730 ASSERT_TRUE(listener_privet->Start());
731
732 ASSERT_TRUE(test_client_->IsListeningForTests());
733
734 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
735 .Times(Exactly(1))
736 .WillOnce(Invoke(
737 &record_privet,
738 &PtrRecordCopyContainer::SaveWithDummyArg));
739
740 SimulatePacketReceive(kSamplePacketAdditionalOnly, sizeof(kSamplePacket1));
741
742 RunUntilIdle();
743
744 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
745 "hello._privet._tcp.local"));
746 }
747
748 TEST_F(MDnsTest, TransactionTimeout) {
749 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
750
751 scoped_ptr<MDnsTransaction> transaction_privet =
752 test_client_->CreateTransaction(
753 dns_protocol::kTypePTR, "_privet._tcp.local",
754 MDnsTransaction::QUERY_NETWORK |
755 MDnsTransaction::QUERY_CACHE |
756 MDnsTransaction::SINGLE_RESULT,
757 base::Bind(&MDnsTest::MockableRecordCallback,
758 base::Unretained(this)));
759
760 ASSERT_TRUE(transaction_privet->Start());
761
762 EXPECT_TRUE(test_client_->IsListeningForTests());
763
764 EXPECT_CALL(*this,
765 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL))
766 .Times(Exactly(1))
767 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
768
769 RunFor(base::TimeDelta::FromSeconds(4));
770
771 EXPECT_FALSE(test_client_->IsListeningForTests());
772 }
773
774 TEST_F(MDnsTest, TransactionMultipleRecords) {
775 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
776
777 scoped_ptr<MDnsTransaction> transaction_privet =
778 test_client_->CreateTransaction(
779 dns_protocol::kTypePTR, "_privet._tcp.local",
780 MDnsTransaction::QUERY_NETWORK |
781 MDnsTransaction::QUERY_CACHE ,
782 base::Bind(&MDnsTest::MockableRecordCallback,
783 base::Unretained(this)));
784
785 ASSERT_TRUE(transaction_privet->Start());
786
787 EXPECT_TRUE(test_client_->IsListeningForTests());
788
789 PtrRecordCopyContainer record_privet;
790 PtrRecordCopyContainer record_privet2;
791
792 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
793 .Times(Exactly(2))
794 .WillOnce(Invoke(&record_privet,
795 &PtrRecordCopyContainer::SaveWithDummyArg))
796 .WillOnce(Invoke(&record_privet2,
797 &PtrRecordCopyContainer::SaveWithDummyArg));
798
799 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
800 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2));
801
802 RunUntilIdle();
803
804 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
805 "hello._privet._tcp.local"));
806
807 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
808 "zzzzz._privet._tcp.local"));
809
810 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL))
811 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
812
813 RunFor(base::TimeDelta::FromSeconds(4));
814
815 EXPECT_FALSE(test_client_->IsListeningForTests());
816 }
817
818 TEST_F(MDnsTest, TransactionReentrantDelete) {
819 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
820
821 transaction_ = test_client_->CreateTransaction(
822 dns_protocol::kTypePTR, "_privet._tcp.local",
823 MDnsTransaction::QUERY_NETWORK |
824 MDnsTransaction::QUERY_CACHE |
825 MDnsTransaction::SINGLE_RESULT,
826 base::Bind(&MDnsTest::MockableRecordCallback,
827 base::Unretained(this)));
828
829 ASSERT_TRUE(transaction_->Start());
830
831 EXPECT_TRUE(test_client_->IsListeningForTests());
832
833 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS,
834 NULL))
835 .Times(Exactly(1))
836 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
837 InvokeWithoutArgs(this, &MDnsTest::Stop)));
838
839 RunFor(base::TimeDelta::FromSeconds(4));
840
841 EXPECT_EQ(NULL, transaction_.get());
842
843 EXPECT_FALSE(test_client_->IsListeningForTests());
844 }
845
846 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
847 StrictMock<MockListenerDelegate> delegate_irrelevant;
848 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
849 dns_protocol::kTypeA, "codereview.chromium.local",
850 &delegate_irrelevant);
851 ASSERT_TRUE(listener_irrelevant->Start());
852
853 ASSERT_TRUE(test_client_->IsListeningForTests());
854
855 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
856
857 transaction_ = test_client_->CreateTransaction(
858 dns_protocol::kTypePTR, "_privet._tcp.local",
859 MDnsTransaction::QUERY_NETWORK |
860 MDnsTransaction::QUERY_CACHE,
861 base::Bind(&MDnsTest::MockableRecordCallback,
862 base::Unretained(this)));
863
864 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
865 .Times(Exactly(1))
866 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
867
868 ASSERT_TRUE(transaction_->Start());
869
870 RunUntilIdle();
871
872 EXPECT_EQ(NULL, transaction_.get());
873 }
874
875 // In order to reliably test reentrant listener deletes, we create two listeners
876 // and have each of them delete both, so we're guaranteed to try and deliver a
877 // callback to at least one deleted listener.
878
879 TEST_F(MDnsTest, ListenerReentrantDelete) {
880 StrictMock<MockListenerDelegate> delegate_privet;
881
882 listener1_ = test_client_->CreateListener(
883 dns_protocol::kTypePTR, "_privet._tcp.local",
884 &delegate_privet);
885
886 listener2_ = test_client_->CreateListener(
887 dns_protocol::kTypePTR, "_privet._tcp.local",
888 &delegate_privet);
889
890 ASSERT_TRUE(listener1_->Start());
891
892 ASSERT_TRUE(listener2_->Start());
893
894 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
895 .Times(Exactly(1))
896 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
897
898 EXPECT_TRUE(test_client_->IsListeningForTests());
899
900 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
901
902 RunUntilIdle();
903
904 EXPECT_EQ(NULL, listener1_.get());
905 EXPECT_EQ(NULL, listener2_.get());
906
907 EXPECT_FALSE(test_client_->IsListeningForTests());
908 }
909
910 // Note: These tests assume that the ipv4 socket will always be created first.
911 // This is a simplifying assumption based on the way the code works now.
912
913 class SimpleMockSocketFactory
914 : public MDnsConnection::SocketFactory {
915 public:
916 SimpleMockSocketFactory() {
917 }
918 virtual ~SimpleMockSocketFactory() {
919 }
920
921 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
922 scoped_ptr<MockDatagramServerSocket> socket(
923 new StrictMock<MockDatagramServerSocket>);
924 sockets_.push(socket.get());
925 return socket.PassAs<DatagramServerSocket>();
926 }
927
928 MockDatagramServerSocket* PopFirstSocket() {
929 MockDatagramServerSocket* socket = sockets_.front();
930 sockets_.pop();
931 return socket;
932 }
933
934 size_t num_sockets() {
935 return sockets_.size();
936 }
937
938 private:
939 std::queue<MockDatagramServerSocket*> sockets_;
940 };
941
942 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
943 public:
944 virtual void HandlePacket(DnsResponse* response, int size) {
945 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
946 }
947
948 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
949
950 MOCK_METHOD1(OnConnectionError, void(int error));
951 };
952
953 class MDnsConnectionTest : public ::testing::Test {
954 public:
955 MDnsConnectionTest() : connection_(&factory_, &delegate_) {
956 }
957
958 protected:
959 // Follow successful connection initialization.
960 virtual void SetUp() OVERRIDE {
961 ASSERT_EQ(2u, factory_.num_sockets());
962
963 socket_ipv4_ = factory_.PopFirstSocket();
964 socket_ipv6_ = factory_.PopFirstSocket();
965 }
966
967 bool InitConnection() {
968 EXPECT_CALL(*socket_ipv4_, AllowAddressReuse());
969 EXPECT_CALL(*socket_ipv6_, AllowAddressReuse());
970
971 EXPECT_CALL(*socket_ipv4_, SetMulticastLoopbackMode(false));
972 EXPECT_CALL(*socket_ipv6_, SetMulticastLoopbackMode(false));
973
974 EXPECT_CALL(*socket_ipv4_, ListenInternal("0.0.0.0:5353"))
975 .WillOnce(Return(OK));
976 EXPECT_CALL(*socket_ipv6_, ListenInternal("[::]:5353"))
977 .WillOnce(Return(OK));
978
979 EXPECT_CALL(*socket_ipv4_, JoinGroupInternal("224.0.0.251"))
980 .WillOnce(Return(OK));
981 EXPECT_CALL(*socket_ipv6_, JoinGroupInternal("ff02::fb"))
982 .WillOnce(Return(OK));
983
984 return connection_.Init() == OK;
985 }
986
987 StrictMock<MockMDnsConnectionDelegate> delegate_;
988
989 MockDatagramServerSocket* socket_ipv4_;
990 MockDatagramServerSocket* socket_ipv6_;
991 SimpleMockSocketFactory factory_;
992 MDnsConnection connection_;
993 TestCompletionCallback callback_;
994 };
995
996 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
997 std::string sample_packet =
998 std::string(kSamplePacket1, sizeof(kSamplePacket1));
999
1000 socket_ipv6_->SetResponsePacket(sample_packet);
1001 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1002 .WillOnce(Return(ERR_IO_PENDING));
1003 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1004 .WillOnce(
1005 Invoke(socket_ipv6_, &MockDatagramServerSocket::HandleRecvNow))
1006 .WillOnce(Return(ERR_IO_PENDING));
1007
1008 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1009
1010 ASSERT_TRUE(InitConnection());
1011 }
1012
1013 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1014 std::string sample_packet =
1015 std::string(kSamplePacket1, sizeof(kSamplePacket1));
1016 socket_ipv6_->SetResponsePacket(sample_packet);
1017 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1018 .WillOnce(Return(ERR_IO_PENDING));
1019 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1020 .WillOnce(
1021 Invoke(socket_ipv6_, &MockDatagramServerSocket::HandleRecvLater))
1022 .WillOnce(Return(ERR_IO_PENDING));
1023
1024 ASSERT_TRUE(InitConnection());
1025
1026 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1027
1028 base::MessageLoop::current()->RunUntilIdle();
1029 }
1030
1031 TEST_F(MDnsConnectionTest, Send) {
1032 std::string sample_packet =
1033 std::string(kSamplePacket1, sizeof(kSamplePacket1));
1034
1035 scoped_refptr<IOBufferWithSize> buf(
1036 new IOBufferWithSize(sizeof kSamplePacket1));
1037 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1038
1039 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1040 .WillOnce(Return(ERR_IO_PENDING));
1041 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1042 .WillOnce(Return(ERR_IO_PENDING));
1043
1044 ASSERT_TRUE(InitConnection());
1045
1046 EXPECT_CALL(*socket_ipv4_,
1047 SendToInternal(sample_packet, "224.0.0.251:5353", _));
1048 EXPECT_CALL(*socket_ipv6_,
1049 SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1050
1051 connection_.Send(buf, buf->size());
1052 }
1053
1054 TEST_F(MDnsConnectionTest, Error) {
1055 CompletionCallback callback;
1056
1057 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1058 .WillOnce(Return(ERR_IO_PENDING));
1059 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1060 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1061
1062 ASSERT_TRUE(InitConnection());
1063
1064 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1065 callback.Run(ERR_SOCKET_NOT_CONNECTED);
1066 }
1067
1068 } // namespace
1069
1070 } // namespace net
OLDNEW
« net/dns/mdns_client_impl.cc ('K') | « net/dns/mdns_client_impl.cc ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698