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

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 int Listen(const IPEndPoint& address) {
szym 2013/06/12 21:35:41 // DatagramServerSocket implementation
Noam Samuel 2013/06/13 01:08:40 Done.
235 return ListenInternal(address.ToString());
236 }
237
238 MOCK_METHOD1(ListenInternal, int(const std::string& address));
239
240 void SetResponsePacket(std::string response_packet) {
szym 2013/06/12 21:35:41 These are not part of DatagramServerSocket so move
Noam Samuel 2013/06/13 01:08:40 Done.
241 response_packet_ = response_packet;
242 }
243
244 int RespondImmediately(IOBuffer* buffer, int size, IPEndPoint* address,
szym 2013/06/12 21:35:41 The name is confusing. How about HandleRecv? Handl
Noam Samuel 2013/06/13 01:08:40 Done.
245 const CompletionCallback& callback) {
246 int to_copy = std::min(response_packet_.size(), (size_t)size);
szym 2013/06/12 21:35:41 size_returned would be more clear than to_copy st
Noam Samuel 2013/06/13 01:08:40 Done.
247 memcpy(buffer->data(), response_packet_.data(), to_copy);
248 return to_copy;
249 }
250
251 int RespondDelayed(IOBuffer* buffer, int size, IPEndPoint* address,
252 const CompletionCallback& callback) {
253 int rv = RespondImmediately(buffer, size, address, callback);
254 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, rv));
255 return ERR_IO_PENDING;
256 }
257
258 MOCK_METHOD4(RecvFrom, int(IOBuffer* buffer, int size,
259 IPEndPoint* address,
260 const CompletionCallback& callback));
261
262 int SendTo(IOBuffer* buf, int buf_len, const IPEndPoint& address,
263 const CompletionCallback& callback) {
264 return SendToInternal(std::string(buf->data(), buf_len), address.ToString(),
265 callback);
266 }
267
268 MOCK_METHOD3(SendToInternal, int(const std::string& packet,
269 const std::string address,
270 const CompletionCallback& callback));
271
272 MOCK_METHOD1(SetReceiveBufferSize, bool(int32 size));
273 MOCK_METHOD1(SetSendBufferSize, bool(int32 size));
274
275 MOCK_METHOD0(Close, void());
276
277 MOCK_CONST_METHOD1(GetPeerAddress, int(IPEndPoint* address));
278 MOCK_CONST_METHOD1(GetLocalAddress, int(IPEndPoint* address));
279 MOCK_CONST_METHOD0(NetLog, const BoundNetLog&());
280
281 MOCK_METHOD0(AllowAddressReuse, void());
282 MOCK_METHOD0(AllowBroadcast, void());
283
284 int JoinGroup(const IPAddressNumber& group_address) const {
285 return JoinGroupInternal(IPAddressToString(group_address));
286 }
287
288 MOCK_CONST_METHOD1(JoinGroupInternal, int(const std::string& group));
289
290 int LeaveGroup(const IPAddressNumber& group_address) const {
291 return LeaveGroupInternal(IPAddressToString(group_address));
292 }
293
294 MOCK_CONST_METHOD1(LeaveGroupInternal, int(const std::string& group));
295
296 MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
297
298 MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
299
300 private:
301 std::string response_packet_;
302 };
303
304 class MockDatagramServerSocketFactory
305 : public MDnsDatagramServerSocketFactory {
306 public:
307 MockDatagramServerSocketFactory() {
308 }
309
310 virtual ~MockDatagramServerSocketFactory() {
311 }
312
313 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
314 scoped_ptr<MockDatagramServerSocket> new_socket(
315 new NiceMock<MockDatagramServerSocket>);
316
317 ON_CALL(*new_socket, SendToInternal(_, _, _))
318 .WillByDefault(Invoke(
319 this,
320 &MockDatagramServerSocketFactory::SendToInternal));
321
322 ON_CALL(*new_socket, RecvFrom(_, _, _, _))
323 .WillByDefault(Invoke(
324 this,
325 &MockDatagramServerSocketFactory::RecvFromInternal));
326
327 return new_socket.PassAs<DatagramServerSocket>();
328 }
329
330 int SendToInternal(const std::string& packet, const std::string& address,
szym 2013/06/12 21:35:41 Does it need to be public?
Noam Samuel 2013/06/13 01:08:40 Done.
331 const CompletionCallback& callback) {
332 OnSendTo(packet);
333 return packet.size();
334 }
335
336 // The latest recieve callback is always saved, since the MDnsConnection
szym 2013/06/12 21:35:41 nit: receive
Noam Samuel 2013/06/13 01:08:40 Done.
337 // does not care which socket a packet is received on.
338 int RecvFromInternal(IOBuffer* buffer, int size,
339 IPEndPoint* address,
340 const CompletionCallback& callback) {
341 recv_buffer_ = buffer;
342 recv_buffer_size_ = size;
343 recv_callback_ = callback;
344 return ERR_IO_PENDING;
345 }
346
347 void SimulateReceive(const char* packet, int size) {
348 DCHECK(recv_buffer_size_ >= size);
349 DCHECK(recv_buffer_.get());
350 DCHECK(!recv_callback_.is_null());
351
352 memcpy(recv_buffer_->data(), packet, size);
353 CompletionCallback recv_callback = recv_callback_;
354 recv_callback_.Reset();
355 recv_callback.Run(size);
356 }
357
358 MOCK_METHOD1(OnSendTo, void(const std::string&));
359
360 private:
361 scoped_refptr<IOBuffer> recv_buffer_;
362 int recv_buffer_size_;
363 CompletionCallback recv_callback_;
364 };
365
366 class PtrRecordCopyContainer {
367 public:
368 PtrRecordCopyContainer() {}
369 ~PtrRecordCopyContainer() {}
370
371 bool is_set() const { return set_; }
372
373 void SaveWithDummyArg(int unused, const RecordParsed* value) {
374 Save(value);
375 }
376
377 void Save(const RecordParsed* value) {
378 set_ = true;
379 name_ = value->name();
380 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain();
381 ttl_ = value->ttl();
382 }
383
384 bool IsRecordWith(std::string name, std::string ptrdomain) {
385 return set_ && name_ == name && ptrdomain_ == ptrdomain;
386 }
387
388 const std::string& name() { return name_; }
389 const std::string& ptrdomain() { return ptrdomain_; }
390 int ttl() { return ttl_; }
391
392 private:
393 bool set_;
394 std::string name_;
395 std::string ptrdomain_;
396 int ttl_;
397 };
398
399 class MDnsTest : public ::testing::Test {
400 public:
401 MDnsTest();
402 virtual ~MDnsTest();
403 void DeleteTransaction();
404 void DeleteBothListeners();
405 void RunUntilIdle();
406 void RunFor(base::TimeDelta time_period);
407 void Stop();
408
409 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransactionResult result,
410 const RecordParsed* record));
411
412 protected:
413 void ExpectPacket(const char* packet, unsigned size);
414 void SimulatePacketRecieve(const char* packet, unsigned size);
szym 2013/06/12 21:35:41 nit: Receive
Noam Samuel 2013/06/13 01:08:40 Done.
415
416 base::MessageLoop* message_loop_;
417
418 scoped_ptr<MDnsClientImpl> test_client_;
419 IPEndPoint mdns_ipv4_endpoint_;
420 StrictMock<MockDatagramServerSocketFactory>* socket_factory_;
421
422 // Transactions and listeners that can be deleted by class methods for
423 // reentrancy tests.
424 scoped_ptr<MDnsTransaction> transaction_;
425 scoped_ptr<MDnsListener> listener1_;
426 scoped_ptr<MDnsListener> listener2_;
427 };
428
429 class MockListenerDelegate : public MDnsListener::Delegate {
430 public:
431 MOCK_METHOD2(OnRecordUpdate,
432 void(MDnsUpdateType update, const RecordParsed* records));
433 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned));
434 MOCK_METHOD0(OnCachePurged, void());
435 };
436
437 MDnsTest::MDnsTest()
438 : message_loop_(base::MessageLoop::current()) {
439 socket_factory_ = new StrictMock<MockDatagramServerSocketFactory>();
440 test_client_.reset(new MDnsClientImpl(socket_factory_));
441 }
442
443 MDnsTest::~MDnsTest() {
444 }
445
446 void MDnsTest::SimulatePacketRecieve(const char* packet, unsigned size) {
447 socket_factory_->SimulateReceive(packet, size);
448 }
449
450 void MDnsTest::ExpectPacket(
451 const char* packet,
452 unsigned size) {
453 EXPECT_CALL(*socket_factory_, OnSendTo(std::string(packet, size)))
454 .Times(2);
455 }
456
457 void MDnsTest::DeleteTransaction() {
458 transaction_.reset();
459 }
460
461 void MDnsTest::DeleteBothListeners() {
462 listener1_.reset();
463 listener2_.reset();
464 }
465
466 void MDnsTest::RunUntilIdle() {
467 base::MessageLoop::current()->RunUntilIdle();
468 }
469
470 void MDnsTest::RunFor(base::TimeDelta time_period) {
471 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
472 base::Unretained(this)));
473 base::MessageLoop::current()->PostDelayedTask(
474 FROM_HERE, callback.callback(), time_period);
475
476 base::MessageLoop::current()->Run();
477 callback.Cancel();
478 }
479
480 void MDnsTest::Stop() {
481 base::MessageLoop::current()->Quit();
482 }
483
484 TEST_F(MDnsTest, PassiveListeners) {
485 StrictMock<MockListenerDelegate> delegate_privet;
486 StrictMock<MockListenerDelegate> delegate_printer;
487 StrictMock<MockListenerDelegate> delegate_ptr;
488
489 PtrRecordCopyContainer record_privet;
490 PtrRecordCopyContainer record_printer;
491
492 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
493 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
494 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
495 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
496 scoped_ptr<MDnsListener> listener_ptr = test_client_->CreateListener(
497 dns_protocol::kTypePTR, "", &delegate_ptr);
498
499 listener_privet->Start();
szym 2013/06/12 21:35:41 Should you ASSERT_TRUE all Start() calls (both lis
Noam Samuel 2013/06/13 01:08:40 Done.
500 listener_printer->Start();
501 listener_ptr->Start();
502
503 ASSERT_TRUE(test_client_->IsListeningForTests());
504
505 // Send the same packet twice to ensure no records are double-counted.
506
507 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _))
508 .Times(Exactly(1))
509 .WillOnce(Invoke(
510 &record_privet,
511 &PtrRecordCopyContainer::SaveWithDummyArg));
512
513 EXPECT_CALL(delegate_printer, OnRecordUpdate(kMDnsRecordAdded, _))
514 .Times(Exactly(1))
515 .WillOnce(Invoke(
516 &record_printer,
517 &PtrRecordCopyContainer::SaveWithDummyArg));
518
519 EXPECT_CALL(delegate_ptr, OnRecordUpdate(kMDnsRecordAdded, _))
520 .Times(Exactly(2));
521
522 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
523 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
524
525 RunUntilIdle();
szym 2013/06/12 21:35:41 I don't think you need to run the loop here. It sh
Noam Samuel 2013/06/13 01:08:40 Done.
526
527 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
528 "hello._privet._tcp.local"));
529
530 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
531 "hello._printer._tcp.local"));
532
533 listener_privet.reset();
534 listener_printer.reset();
535
536 ASSERT_TRUE(test_client_->IsListeningForTests());
537
538 EXPECT_CALL(delegate_ptr, OnRecordUpdate(kMDnsRecordAdded, _))
539 .Times(Exactly(2));
540
541 SimulatePacketRecieve(kSamplePacket2, sizeof(kSamplePacket2));
542
543 RunUntilIdle();
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, PassiveListenersCleanup) {
szym 2013/06/12 21:35:41 I suggest PassiveListenersCacheCleanup.
Noam Samuel 2013/06/13 01:08:40 Done.
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 listener_privet->Start();
563
564 ASSERT_TRUE(test_client_->IsListeningForTests());
565
566 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _))
567 .Times(Exactly(1))
568 .WillOnce(Invoke(
569 &record_privet,
570 &PtrRecordCopyContainer::SaveWithDummyArg));
571
572 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
573
574 RunUntilIdle();
575
576 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
577 "hello._privet._tcp.local"));
578
579 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordRemoved, _))
szym 2013/06/12 21:35:41 Add a comment "Expect record is removed when its T
Noam Samuel 2013/06/13 01:08:40 Done.
580 .Times(Exactly(1))
581 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop),
582 Invoke(&record_privet2,
583 &PtrRecordCopyContainer::SaveWithDummyArg)));
584
585 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1));
586
587 RunUntilIdle();
588
589 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
590 "hello._privet._tcp.local"));
591 }
592
593 TEST_F(MDnsTest, MalformedPacket) {
594 StrictMock<MockListenerDelegate> delegate_printer;
595
596 PtrRecordCopyContainer record_printer;
597
598 scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
599 dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
600
601 listener_printer->Start();
602
603 ASSERT_TRUE(test_client_->IsListeningForTests());
604
605 EXPECT_CALL(delegate_printer, OnRecordUpdate(kMDnsRecordAdded, _))
606 .Times(Exactly(1))
607 .WillOnce(Invoke(
608 &record_printer,
609 &PtrRecordCopyContainer::SaveWithDummyArg));
610
611 // First, send unsalvagable packet to ensure we can deal with it.
612 SimulatePacketRecieve(kCorruptedPacketUnsalvagable,
613 sizeof(kCorruptedPacketUnsalvagable));
614
615 // Regression test: send a packet where the question cannot be read.
616 SimulatePacketRecieve(kCorruptedPacketBadQuestion,
617 sizeof(kCorruptedPacketBadQuestion));
618
619 // Then send salvagable packet to ensure we can extract useful records.
620 SimulatePacketRecieve(kCorruptedPacketSalvagable,
621 sizeof(kCorruptedPacketSalvagable));
622
623 RunUntilIdle();
624
625 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local",
626 "hello._printer._tcp.local"));
627 }
628
629 TEST_F(MDnsTest, TransactionNoCache) {
szym 2013/06/12 21:35:41 I suggest TransactionWithEmptyCache
Noam Samuel 2013/06/13 01:08:40 Done.
630 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
631
632 scoped_ptr<MDnsTransaction> transaction_privet =
633 test_client_->CreateTransaction(
634 dns_protocol::kTypePTR, "_privet._tcp.local",
635 kMDnsTransactionQueryNetwork |
636 kMDnsTransactionQueryCache |
637 kMDnsTransactionSingleResult,
638 base::Bind(&MDnsTest::MockableRecordCallback,
639 base::Unretained(this)));
640
641 transaction_privet->Start();
642
643 EXPECT_TRUE(test_client_->IsListeningForTests());
644
645 PtrRecordCopyContainer record_privet;
646
647 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionRecord, _))
648 .Times(Exactly(1))
649 .WillOnce(Invoke(&record_privet,
650 &PtrRecordCopyContainer::SaveWithDummyArg));
651
652 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
653
654 RunUntilIdle();
655
656 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
657 "hello._privet._tcp.local"));
658
659 EXPECT_FALSE(test_client_->IsListeningForTests());
660 }
661
662 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
663 scoped_ptr<MDnsTransaction> transaction_privet =
664 test_client_->CreateTransaction(
665 dns_protocol::kTypePTR, "_privet._tcp.local",
666 kMDnsTransactionQueryCache |
667 kMDnsTransactionSingleResult,
668 base::Bind(&MDnsTest::MockableRecordCallback,
669 base::Unretained(this)));
670
671 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionNoResults, _))
672 .Times(Exactly(1));
673
674 transaction_privet->Start();
675
676 EXPECT_FALSE(test_client_->IsListeningForTests());
677
678 RunUntilIdle();
679 }
680
681 TEST_F(MDnsTest, TransactionWithCache) {
682 // Listener to force the client to listen
683 StrictMock<MockListenerDelegate> delegate_irrelevant;
684 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
685 dns_protocol::kTypeA, "codereview.chromium.local",
686 &delegate_irrelevant);
687
688 listener_irrelevant->Start();
689
690 EXPECT_TRUE(test_client_->IsListeningForTests());
691
692 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
693
694 RunUntilIdle();
695
696 PtrRecordCopyContainer record_privet;
697
698 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionRecord, _))
699 .WillOnce(Invoke(&record_privet,
700 &PtrRecordCopyContainer::SaveWithDummyArg));
701
702 scoped_ptr<MDnsTransaction> transaction_privet =
703 test_client_->CreateTransaction(
704 dns_protocol::kTypePTR, "_privet._tcp.local",
705 kMDnsTransactionQueryNetwork |
706 kMDnsTransactionQueryCache |
707 kMDnsTransactionSingleResult,
708 base::Bind(&MDnsTest::MockableRecordCallback,
709 base::Unretained(this)));
710
711 transaction_privet->Start();
712
713 RunUntilIdle();
714
715 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
716 "hello._privet._tcp.local"));
717 }
718
719 TEST_F(MDnsTest, AdditionalRecords) {
720 StrictMock<MockListenerDelegate> delegate_privet;
721
722 PtrRecordCopyContainer record_privet;
723
724 scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
725 dns_protocol::kTypePTR, "_privet._tcp.local",
726 &delegate_privet);
727
728 listener_privet->Start();
729
730 ASSERT_TRUE(test_client_->IsListeningForTests());
731
732 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _))
733 .Times(Exactly(1))
734 .WillOnce(Invoke(
735 &record_privet,
736 &PtrRecordCopyContainer::SaveWithDummyArg));
737
738 SimulatePacketRecieve(kSamplePacketAdditionalOnly, sizeof(kSamplePacket1));
739
740 RunUntilIdle();
741
742 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
743 "hello._privet._tcp.local"));
744 }
745
746 TEST_F(MDnsTest, TransactionTimeout) {
747 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
748
749 scoped_ptr<MDnsTransaction> transaction_privet =
750 test_client_->CreateTransaction(
751 dns_protocol::kTypePTR, "_privet._tcp.local",
752 kMDnsTransactionQueryNetwork |
753 kMDnsTransactionQueryCache |
754 kMDnsTransactionSingleResult,
755 base::Bind(&MDnsTest::MockableRecordCallback,
756 base::Unretained(this)));
757
758 transaction_privet->Start();
759
760 EXPECT_TRUE(test_client_->IsListeningForTests());
761
762 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionNoResults, NULL))
763 .Times(Exactly(1))
764 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
765
766 RunFor(base::TimeDelta::FromSeconds(4));
767
768 EXPECT_FALSE(test_client_->IsListeningForTests());
769 }
770
771 TEST_F(MDnsTest, TransactionMultipleRecords) {
772 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
773
774 scoped_ptr<MDnsTransaction> transaction_privet =
775 test_client_->CreateTransaction(
776 dns_protocol::kTypePTR, "_privet._tcp.local",
777 kMDnsTransactionQueryNetwork |
778 kMDnsTransactionQueryCache ,
779 base::Bind(&MDnsTest::MockableRecordCallback,
780 base::Unretained(this)));
781
782 transaction_privet->Start();
783
784 EXPECT_TRUE(test_client_->IsListeningForTests());
785
786 PtrRecordCopyContainer record_privet;
787 PtrRecordCopyContainer record_privet2;
788
789 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionRecord, _))
790 .Times(Exactly(2))
791 .WillOnce(Invoke(&record_privet,
792 &PtrRecordCopyContainer::SaveWithDummyArg))
793 .WillOnce(Invoke(&record_privet2,
794 &PtrRecordCopyContainer::SaveWithDummyArg));
795
796 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
797 SimulatePacketRecieve(kSamplePacket2, sizeof(kSamplePacket2));
798
799 RunUntilIdle();
800
801 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local",
802 "hello._privet._tcp.local"));
803
804 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local",
805 "zzzzz._privet._tcp.local"));
806
807 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionDone, NULL))
808 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop));
809
810 RunFor(base::TimeDelta::FromSeconds(4));
811
812 EXPECT_FALSE(test_client_->IsListeningForTests());
813 }
814
815 TEST_F(MDnsTest, TransactionReentrantDelete) {
816 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
817
818 transaction_ = test_client_->CreateTransaction(
819 dns_protocol::kTypePTR, "_privet._tcp.local",
820 kMDnsTransactionQueryNetwork |
821 kMDnsTransactionQueryCache |
822 kMDnsTransactionSingleResult,
823 base::Bind(&MDnsTest::MockableRecordCallback,
824 base::Unretained(this)));
825
826 transaction_->Start();
827
828 EXPECT_TRUE(test_client_->IsListeningForTests());
829
830 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionNoResults, NULL))
831 .Times(Exactly(1))
832 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction),
833 InvokeWithoutArgs(this, &MDnsTest::Stop)));
834
835 RunFor(base::TimeDelta::FromSeconds(4));
836
837 EXPECT_EQ(NULL, transaction_.get());
838
839 EXPECT_FALSE(test_client_->IsListeningForTests());
840 }
841
842 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
843 StrictMock<MockListenerDelegate> delegate_irrelevant;
844 scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
845 dns_protocol::kTypeA, "codereview.chromium.local",
846 &delegate_irrelevant);
847 listener_irrelevant->Start();
848
849 ASSERT_TRUE(test_client_->IsListeningForTests());
850
851 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
852
853 transaction_ = test_client_->CreateTransaction(
854 dns_protocol::kTypePTR, "_privet._tcp.local",
855 kMDnsTransactionQueryNetwork |
856 kMDnsTransactionQueryCache,
857 base::Bind(&MDnsTest::MockableRecordCallback,
858 base::Unretained(this)));
859
860 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionRecord, _))
861 .Times(Exactly(1))
862 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction));
863
864 transaction_->Start();
865
866 RunUntilIdle();
867
868 EXPECT_EQ(NULL, transaction_.get());
869 }
870
871 // In order to reliably test reentrant listener deletes, we create two listeners
872 // and have each of them delete both, so we're guaranteed to try and deliver a
873 // callback to at least one deleted listener.
874
875 TEST_F(MDnsTest, ListenerReentrantDelete) {
876 StrictMock<MockListenerDelegate> delegate_privet;
877
878 listener1_ = test_client_->CreateListener(
879 dns_protocol::kTypePTR, "_privet._tcp.local",
880 &delegate_privet);
881
882 listener2_ = test_client_->CreateListener(
883 dns_protocol::kTypePTR, "_privet._tcp.local",
884 &delegate_privet);
885
886 listener1_->Start();
887
888 listener2_->Start();
889
890 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _))
891 .Times(Exactly(1))
892 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners));
893
894 EXPECT_TRUE(test_client_->IsListeningForTests());
895
896 SimulatePacketRecieve(kSamplePacket1, sizeof(kSamplePacket1));
897
898 RunUntilIdle();
899
900 EXPECT_EQ(NULL, listener1_.get());
901 EXPECT_EQ(NULL, listener2_.get());
902
903 EXPECT_FALSE(test_client_->IsListeningForTests());
904 }
905
906 // Note: These tests assume that the ipv4 socket will always be created first.
907 // This is a simplifying assumption based on the way the code works now.
908
909 class SimpleMockDatagramServerSocketFactory
910 : public MDnsDatagramServerSocketFactory {
911 public:
912 SimpleMockDatagramServerSocketFactory() {
913 }
914 virtual ~SimpleMockDatagramServerSocketFactory() {
915 }
916
917 virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
918 scoped_ptr<MockDatagramServerSocket> socket(
919 new StrictMock<MockDatagramServerSocket>);
920 sockets_.push(socket.get());
921 return socket.PassAs<DatagramServerSocket>();
922 }
923
924 MockDatagramServerSocket* PopFirstSocket() {
925 MockDatagramServerSocket* socket = sockets_.front();
szym 2013/06/12 21:35:41 It'd be nice if you could ensure test failure with
Noam Samuel 2013/06/13 01:08:40 Replaced with assert. Verified no crash.
926 sockets_.pop();
927 return socket;
928 }
929
930 size_t num_sockets() {
931 return sockets_.size();
932 }
933
934 private:
935 std::queue<MockDatagramServerSocket*> sockets_;
936 };
937
938 class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
939 public:
940 virtual void HandlePacket(DnsResponse* response, int size) {
941 HandlePacketInternal(std::string(response->io_buffer()->data(), size));
942 }
943
944 MOCK_METHOD1(HandlePacketInternal, void(std::string packet));
945
946 MOCK_METHOD1(OnConnectionError, void(int error));
947 };
948
949 class MDnsConnectionTest : public ::testing::Test {
950 public:
951 MDnsConnectionTest() : connection_(&factory_, &delegate_) {
952 }
953
954 protected:
955 // Follow successful connection initialization
szym 2013/06/12 21:35:41 nit: end with "."
Noam Samuel 2013/06/13 01:08:40 Done.
956 virtual void SetUp() OVERRIDE {
957 EXPECT_EQ(2u, factory_.num_sockets());
958
959 socket_ipv4_ = factory_.PopFirstSocket();
960 socket_ipv6_ = factory_.PopFirstSocket();
961 }
962
963 void InitConnection() {
964 EXPECT_CALL(*socket_ipv4_, AllowAddressReuse());
965 EXPECT_CALL(*socket_ipv6_, AllowAddressReuse());
966
967 EXPECT_CALL(*socket_ipv4_, SetMulticastLoopbackMode(false));
968 EXPECT_CALL(*socket_ipv6_, SetMulticastLoopbackMode(false));
969
970 EXPECT_CALL(*socket_ipv4_, ListenInternal("0.0.0.0:5353"))
971 .WillOnce(Return(OK));
972 EXPECT_CALL(*socket_ipv6_, ListenInternal("[::]:5353"))
973 .WillOnce(Return(OK));
974
975 EXPECT_CALL(*socket_ipv4_, JoinGroupInternal("224.0.0.251"))
976 .WillOnce(Return(OK));
977 EXPECT_CALL(*socket_ipv6_, JoinGroupInternal("ff02::fb"))
978 .WillOnce(Return(OK));
979
980 connection_.Init();
szym 2013/06/12 21:35:41 I suggest you return the value or (return connecti
Noam Samuel 2013/06/13 01:08:40 Done.
981 }
982
983 StrictMock<MockMDnsConnectionDelegate> delegate_;
984
985 MockDatagramServerSocket* socket_ipv4_;
986 MockDatagramServerSocket* socket_ipv6_;
987 SimpleMockDatagramServerSocketFactory factory_;
988 MDnsConnection connection_;
989 TestCompletionCallback callback_;
990 };
991
992 TEST_F(MDnsConnectionTest, ReceiveSynchronous) {
993 std::string sample_packet =
994 std::string(kSamplePacket1, sizeof(kSamplePacket1));
995
996 socket_ipv6_->SetResponsePacket(sample_packet);
997 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
998 .WillOnce(Return(ERR_IO_PENDING));
999 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1000 .WillOnce(
1001 Invoke(socket_ipv6_, &MockDatagramServerSocket::RespondImmediately))
1002 .WillOnce(Return(ERR_IO_PENDING));
1003
1004 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1005
1006 InitConnection();
1007 }
1008
1009 TEST_F(MDnsConnectionTest, ReceiveAsynchronous) {
1010 std::string sample_packet =
1011 std::string(kSamplePacket1, sizeof(kSamplePacket1));
1012 socket_ipv6_->SetResponsePacket(sample_packet);
1013 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1014 .WillOnce(Return(ERR_IO_PENDING));
1015 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1016 .WillOnce(
1017 Invoke(socket_ipv6_, &MockDatagramServerSocket::RespondDelayed))
1018 .WillOnce(Return(ERR_IO_PENDING));
1019
1020 InitConnection();
1021
1022 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet));
1023
1024 base::MessageLoop::current()->RunUntilIdle();
1025 }
1026
1027 TEST_F(MDnsConnectionTest, Send) {
1028 std::string sample_packet =
1029 std::string(kSamplePacket1, sizeof(kSamplePacket1));
1030
1031 scoped_refptr<IOBufferWithSize> buf(
1032 new IOBufferWithSize(sizeof kSamplePacket1));
1033 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1));
1034
1035 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1036 .WillOnce(Return(ERR_IO_PENDING));
1037 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1038 .WillOnce(Return(ERR_IO_PENDING));
1039
1040 InitConnection();
1041
1042 EXPECT_CALL(*socket_ipv4_,
1043 SendToInternal(sample_packet, "224.0.0.251:5353", _));
1044 EXPECT_CALL(*socket_ipv6_,
1045 SendToInternal(sample_packet, "[ff02::fb]:5353", _));
1046
1047 connection_.Send(buf, buf->size());
1048 }
1049
1050 TEST_F(MDnsConnectionTest, Error) {
1051 CompletionCallback callback;
1052
1053 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _))
1054 .WillOnce(Return(ERR_IO_PENDING));
1055 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _))
1056 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING)));
1057
1058 InitConnection();
1059
1060 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED));
1061 callback.Run(ERR_SOCKET_NOT_CONNECTED);
1062 }
1063
1064 } // namespace
1065
1066 } // 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