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

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

Powered by Google App Engine
This is Rietveld 408576698