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