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_listener_impl.h" | |
10 #include "net/dns/record_rdata.h" | |
11 #include "net/test/fake_time_system.h" | |
12 #include "net/udp/udp_client_socket.h" | |
13 #include "testing/gmock/include/gmock/gmock.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 using ::testing::Invoke; | |
17 using ::testing::InvokeWithoutArgs; | |
18 using ::testing::StrictMock; | |
19 using ::testing::Exactly; | |
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, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. | |
43 0x24, 0x74, | |
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 | |
229 // Connect to any port on an address. Returns the bound address. | |
230 IPEndPoint BindToAnyPort(UDPSocket* socket, | |
231 const IPAddressNumber& address) { | |
232 IPEndPoint endpoint(address, 0); | |
233 int status = socket->Bind(endpoint); | |
234 DCHECK(status == OK); | |
235 status = socket->GetLocalAddress(&endpoint); | |
236 DCHECK(status == OK); | |
237 | |
238 return endpoint; | |
239 } | |
240 | |
241 class TestableMDnsListenerFactoryImpl : public MDnsListenerFactoryImpl { | |
242 public: | |
243 explicit TestableMDnsListenerFactoryImpl(FakeTimeSystem* time_system) | |
244 : MDnsListenerFactoryImpl(time_system, time_system) { | |
245 } | |
246 | |
247 void SetIPv4SendEndpoint(const IPEndPoint& ipv4_send_endpoint) { | |
248 ipv4_send_endpoint_ = ipv4_send_endpoint; | |
249 } | |
250 | |
251 void SetIPv6SendEndpoint(const IPEndPoint& ipv6_send_endpoint) { | |
252 ipv6_send_endpoint_ = ipv6_send_endpoint; | |
253 } | |
254 | |
255 IPEndPoint ipv4_bind_endpoint() { return ipv4_bind_endpoint_; } | |
256 | |
257 protected: | |
258 virtual IPEndPoint GetIPv4SendEndpoint() OVERRIDE { | |
259 return ipv4_send_endpoint_; | |
260 } | |
261 | |
262 virtual IPEndPoint GetIPv6SendEndpoint() OVERRIDE { | |
263 return ipv6_send_endpoint_; | |
264 } | |
265 | |
266 virtual bool BindToAddressAndMulticastGroup( | |
267 UDPSocket* socket, | |
268 const IPEndPoint& address, | |
269 const IPAddressNumber& group) OVERRIDE { | |
270 // Bind only to local address. Use address length to determine protocol. | |
271 IPAddressNumber local_address; | |
272 if (address.address().size() == kIPv4AddressSize) { | |
273 bool success = ParseIPLiteralToNumber("127.0.0.1", | |
274 &local_address); | |
275 DCHECK(success); | |
276 } else { | |
277 DCHECK(address.address().size() == kIPv6AddressSize); | |
278 bool success = ParseIPLiteralToNumber("::1", | |
279 &local_address); | |
280 DCHECK(success); | |
281 } | |
282 | |
283 IPEndPoint bound_endpoint = BindToAnyPort(socket, local_address); | |
284 if (address.address().size() == kIPv4AddressSize) { | |
285 ipv4_bind_endpoint_ = bound_endpoint; | |
286 } | |
287 return true; | |
288 } | |
289 | |
290 private: | |
291 IPEndPoint ipv4_send_endpoint_; | |
292 IPEndPoint ipv6_send_endpoint_; | |
293 IPEndPoint ipv4_bind_endpoint_; | |
294 }; | |
295 | |
296 class RecordParsedCopyContainer { | |
297 public: | |
298 RecordParsedCopyContainer() {} | |
299 ~RecordParsedCopyContainer() {} | |
300 | |
301 bool is_set() const { return value_.get() != NULL; } | |
302 | |
303 void SaveWithDummyArg(int unused, const RecordParsed* value) { | |
304 Save(value); | |
305 } | |
306 | |
307 void Save(const RecordParsed* value) { | |
308 value_ = value->Clone(); | |
309 } | |
310 | |
311 const RecordParsed* operator->() const { | |
312 return value_.get(); | |
313 } | |
314 | |
315 private: | |
316 scoped_ptr<const RecordParsed> value_; | |
317 }; | |
318 | |
319 class MDnsTest : public ::testing::Test { | |
320 public: | |
321 MDnsTest(); | |
322 virtual ~MDnsTest(); | |
323 virtual void SetUp() OVERRIDE; | |
324 virtual void TearDown() OVERRIDE; | |
325 void DeleteTransaction(); | |
326 | |
327 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransactionResult, | |
328 const RecordParsed*)); | |
329 | |
330 protected: | |
331 void ExpectPacket(const char* packet, unsigned size); | |
332 void SendPacket(const char* packet, unsigned size); | |
333 void ExpectPtrRecord( | |
334 const std::string& name, | |
335 const std::string& ptrdomain, | |
336 const RecordParsedCopyContainer& record); | |
337 | |
338 base::MessageLoop* message_loop_; | |
339 scoped_ptr<TestableMDnsListenerFactoryImpl> test_factory_; | |
340 scoped_ptr<UDPSocket> client_socket_; | |
341 scoped_ptr<UDPSocket> server_socket_; | |
342 scoped_ptr<UDPSocket> server_socket6_; | |
343 IPEndPoint mdns_ipv4_endpoint_; | |
344 scoped_refptr<FakeTimeSystem> time_system_; | |
345 | |
346 scoped_ptr<MDnsTransaction> transaction_; | |
347 }; | |
348 | |
349 class MockListenerDelegate : public MDnsListenerFactory::Delegate { | |
350 public: | |
351 MOCK_METHOD2(OnRecordUpdate, | |
352 void(MDnsUpdateType, const RecordParsed*)); | |
353 MOCK_METHOD2(OnNSecRecord, void(const std::string&, unsigned)); | |
354 }; | |
355 | |
356 MDnsTest::MDnsTest() | |
357 : message_loop_(base::MessageLoop::current()), | |
358 client_socket_(new UDPSocket(DatagramSocket::DEFAULT_BIND, | |
359 net::RandIntCallback(), | |
360 NULL, | |
361 net::NetLog::Source())), | |
szym
2013/05/24 15:32:22
To minimize flakiness, we'd test this with MockUDP
Noam Samuel
2013/05/24 21:59:18
Hm. I tend to agree that, in retrospect, using moc
Noam Samuel
2013/05/29 21:25:16
Done.
szym
2013/06/02 19:01:23
I still see UDPSocket rather than DatagramServerSo
Noam Samuel
2013/06/03 17:57:55
DatagramServerSocket doesn't support multicasting
szym
2013/06/03 18:38:30
I think so.
Noam Samuel
2013/06/04 00:08:02
Added support in interface: https://codereview.chr
| |
362 server_socket_(new UDPSocket(DatagramSocket::DEFAULT_BIND, | |
363 net::RandIntCallback(), | |
364 NULL, | |
365 net::NetLog::Source())), | |
366 server_socket6_(new UDPSocket(DatagramSocket::DEFAULT_BIND, | |
367 net::RandIntCallback(), | |
368 NULL, | |
369 net::NetLog::Source())) { | |
370 time_system_ = new FakeTimeSystem(); | |
371 time_system_->SetNow(base::Time::FromDoubleT(1234.0)); | |
372 test_factory_.reset(new TestableMDnsListenerFactoryImpl(time_system_)); | |
373 } | |
374 | |
375 MDnsTest::~MDnsTest() { | |
376 } | |
377 | |
378 void MDnsTest::SetUp() { | |
379 IPAddressNumber loopback4; | |
380 ParseIPLiteralToNumber("127.0.0.1", &loopback4); | |
381 | |
382 IPAddressNumber loopback6; | |
383 ParseIPLiteralToNumber("::1", &loopback6); | |
384 | |
385 test_factory_->SetIPv4SendEndpoint( | |
386 BindToAnyPort(server_socket_.get(), loopback4)); | |
387 test_factory_->SetIPv6SendEndpoint( | |
388 BindToAnyPort(server_socket6_.get(), loopback6)); | |
389 | |
390 client_socket_->Bind(IPEndPoint(loopback4, 0)); | |
391 } | |
392 | |
393 void MDnsTest::TearDown() { | |
394 client_socket_->Close(); | |
szym
2013/05/24 15:32:22
Not necessary. ~MDnsTest (called immediately after
Noam Samuel
2013/05/29 21:25:16
Done.
| |
395 } | |
396 | |
397 void MDnsTest::SendPacket(const char* packet, unsigned size) { | |
398 TestCompletionCallback write_callback; | |
399 | |
400 scoped_refptr<IOBufferWithSize> buffer(new IOBufferWithSize(size)); | |
401 memcpy(buffer->data(), packet, size); | |
402 | |
403 int socket_result = | |
404 client_socket_->SendTo(buffer, | |
405 size, | |
406 test_factory_->ipv4_bind_endpoint(), | |
407 write_callback.callback()); | |
408 | |
409 if (socket_result == ERR_IO_PENDING) { | |
410 socket_result = write_callback.WaitForResult(); | |
411 } | |
412 | |
413 ASSERT_EQ(size, static_cast<unsigned>(socket_result)); | |
414 | |
415 // Since the network layer uses MessageLoop, we RunUntilIdle here | |
416 // so the tests do not have to. | |
417 MessageLoop::current()->RunUntilIdle(); | |
418 } | |
419 | |
420 void MDnsTest::ExpectPtrRecord( | |
421 const std::string& name, | |
422 const std::string& ptrdomain, | |
423 const RecordParsedCopyContainer& record) { | |
424 EXPECT_TRUE(record.is_set()); | |
425 EXPECT_EQ(name, record->name()); | |
426 EXPECT_EQ(dns_protocol::kTypePTR, record->type()); | |
427 EXPECT_EQ(dns_protocol::kClassIN, record->klass()); | |
428 const PtrRecordRdata* rdata = record->rdata<PtrRecordRdata>(); | |
429 EXPECT_TRUE(rdata != NULL); | |
430 EXPECT_EQ(ptrdomain, rdata->ptrdomain()); | |
431 } | |
432 | |
433 void MDnsTest::ExpectPacket( | |
434 const char* packet, | |
435 unsigned size) { | |
436 TestCompletionCallback recv_callback; | |
437 IPEndPoint recv_endpoint; | |
438 scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(size); | |
439 int rv; | |
440 | |
441 do { | |
442 rv = server_socket_->RecvFrom(buf.get(), buf->size(), | |
443 &recv_endpoint, recv_callback.callback()); | |
444 | |
445 if (rv == ERR_IO_PENDING) { | |
446 rv = recv_callback.WaitForResult(); | |
447 } | |
448 DCHECK_GT(rv, 0); | |
449 // This is an easy way to compare to addresses for a test. | |
450 } while (recv_endpoint.ToString() != | |
451 test_factory_->ipv4_bind_endpoint().ToString()); | |
452 | |
453 ASSERT_EQ(static_cast<int>(size), rv); | |
454 ASSERT_EQ(0, memcmp(packet, buf->data(), size)); | |
455 } | |
456 | |
457 void MDnsTest::DeleteTransaction() { | |
458 transaction_.reset(); | |
459 } | |
460 | |
461 TEST_F(MDnsTest, PassiveListeners) { | |
462 StrictMock<MockListenerDelegate> delegate_privet; | |
463 StrictMock<MockListenerDelegate> delegate_printer; | |
464 StrictMock<MockListenerDelegate> delegate_ptr; | |
465 | |
466 RecordParsedCopyContainer record_privet; | |
467 RecordParsedCopyContainer record_printer; | |
468 | |
469 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
470 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
471 &delegate_privet); | |
472 scoped_ptr<MDnsListener> listener_printer = test_factory_->CreateListener( | |
473 dns_protocol::kTypePTR, "_printer._tcp.local", false, false, | |
474 &delegate_printer); | |
475 scoped_ptr<MDnsListener> listener_ptr = test_factory_->CreateListener( | |
476 dns_protocol::kTypePTR, "", false, false, &delegate_ptr); | |
477 | |
478 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
479 | |
480 // Send the same packet twice to ensure no records are double-counted. | |
481 | |
482 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
483 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
484 | |
485 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _)) | |
486 .Times(Exactly(1)) | |
487 .WillOnce(Invoke( | |
488 &record_privet, | |
489 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
490 | |
491 EXPECT_CALL(delegate_printer, OnRecordUpdate(kMDnsRecordAdded, _)) | |
492 .Times(Exactly(1)) | |
493 .WillOnce(Invoke( | |
494 &record_printer, | |
495 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
496 | |
497 EXPECT_CALL(delegate_ptr, OnRecordUpdate(kMDnsRecordAdded, _)) | |
498 .Times(Exactly(2)); | |
499 | |
500 time_system_->RunPendingTasks(); | |
501 | |
502 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
503 record_privet); | |
504 | |
505 ExpectPtrRecord("_printer._tcp.local", "hello._printer._tcp.local", | |
506 record_printer); | |
507 | |
508 listener_privet.reset(); | |
509 listener_printer.reset(); | |
510 | |
511 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
512 | |
513 EXPECT_CALL(delegate_ptr, OnRecordUpdate(kMDnsRecordAdded, _)) | |
514 .Times(Exactly(2)); | |
515 | |
516 SendPacket(kSamplePacket2, sizeof(kSamplePacket2)); | |
517 | |
518 time_system_->RunPendingTasks(); | |
519 | |
520 // Test to make sure mdns listener is not active with no listeners present. | |
521 listener_ptr.reset(); | |
522 | |
523 ASSERT_FALSE(test_factory_->IsListeningForTests()); | |
524 } | |
525 | |
526 TEST_F(MDnsTest, PassiveListenersCleanup) { | |
527 StrictMock<MockListenerDelegate> delegate_privet; | |
528 | |
529 RecordParsedCopyContainer record_privet; | |
530 RecordParsedCopyContainer record_privet2; | |
531 | |
532 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
533 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
534 &delegate_privet); | |
535 | |
536 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
537 | |
538 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
539 | |
540 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _)) | |
541 .Times(Exactly(1)) | |
542 .WillOnce(Invoke( | |
543 &record_privet, | |
544 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
545 | |
546 time_system_->RunPendingTasks(); | |
547 | |
548 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
549 record_privet); | |
550 | |
551 base::Time expiration = time_system_->Now() + base::TimeDelta::FromSeconds( | |
552 record_privet->ttl()); | |
553 | |
554 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordRemoved, _)) | |
555 .Times(Exactly(1)) | |
556 .WillOnce(Invoke( | |
557 &record_privet2, | |
558 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
559 | |
560 time_system_->SetNow(expiration); | |
561 time_system_->RunPendingTasks(); | |
562 | |
563 time_system_->RunPendingTasks(); | |
564 | |
565 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
566 record_privet2); | |
567 } | |
568 | |
569 TEST_F(MDnsTest, PassiveListenersNotifyExisting) { | |
570 StrictMock<MockListenerDelegate> delegate_privet; | |
571 StrictMock<MockListenerDelegate> delegate_privet2; | |
572 | |
573 RecordParsedCopyContainer record_privet; | |
574 RecordParsedCopyContainer record_privet2; | |
575 | |
576 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
577 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
578 &delegate_privet); | |
579 | |
580 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
581 | |
582 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
583 | |
584 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _)) | |
585 .Times(Exactly(1)) | |
586 .WillOnce(Invoke( | |
587 &record_privet, | |
588 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
589 | |
590 time_system_->RunPendingTasks(); | |
591 | |
592 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
593 record_privet); | |
594 | |
595 scoped_ptr<MDnsListener> listener_privet2 = test_factory_->CreateListener( | |
596 dns_protocol::kTypePTR, "_privet._tcp.local", false, true, | |
597 &delegate_privet2); | |
598 | |
599 EXPECT_CALL(delegate_privet2, OnRecordUpdate(kMDnsRecordAdded, _)) | |
600 .Times(Exactly(1)) | |
601 .WillOnce(Invoke( | |
602 &record_privet2, | |
603 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
604 | |
605 time_system_->RunPendingTasks(); | |
606 | |
607 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
608 record_privet2); | |
609 } | |
610 | |
611 TEST_F(MDnsTest, MalformedPacket) { | |
612 StrictMock<MockListenerDelegate> delegate_printer; | |
613 | |
614 RecordParsedCopyContainer record_printer; | |
615 | |
616 scoped_ptr<MDnsListener> listener_printer = test_factory_->CreateListener( | |
617 dns_protocol::kTypePTR, "_printer._tcp.local", false, false, | |
618 &delegate_printer); | |
619 | |
620 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
621 | |
622 // First, send unsalvagable packet to ensure we can deal with it. | |
623 SendPacket(kCorruptedPacketUnsalvagable, | |
624 sizeof(kCorruptedPacketUnsalvagable)); | |
625 | |
626 // Regression test: send a packet where the question cannot be read. | |
627 SendPacket(kCorruptedPacketBadQuestion, | |
628 sizeof(kCorruptedPacketBadQuestion)); | |
629 | |
630 // Then send salvagable packet to ensure we can extract useful records. | |
631 SendPacket(kCorruptedPacketSalvagable, | |
632 sizeof(kCorruptedPacketSalvagable)); | |
633 | |
634 EXPECT_CALL(delegate_printer, OnRecordUpdate(kMDnsRecordAdded, _)) | |
635 .Times(Exactly(1)) | |
636 .WillOnce(Invoke( | |
637 &record_printer, | |
638 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
639 | |
640 time_system_->RunPendingTasks(); | |
641 | |
642 ExpectPtrRecord("_printer._tcp.local", "hello._printer._tcp.local", | |
643 record_printer); | |
644 } | |
645 | |
646 TEST_F(MDnsTest, QueryCache) { | |
647 StrictMock<MockListenerDelegate> delegate_privet; | |
648 | |
649 RecordParsedCopyContainer record_privet; | |
650 std::vector<const RecordParsed*> records_from_cache; | |
651 | |
652 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
653 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
654 &delegate_privet); | |
655 | |
656 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
657 | |
658 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
659 | |
660 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _)) | |
661 .Times(Exactly(1)) | |
662 .WillOnce(Invoke( | |
663 &record_privet, | |
664 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
665 | |
666 time_system_->RunPendingTasks(); | |
667 | |
668 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
669 record_privet); | |
670 | |
671 listener_privet->QueryCache(&records_from_cache); | |
672 | |
673 EXPECT_EQ(1u, records_from_cache.size()); | |
674 EXPECT_EQ("_privet._tcp.local", records_from_cache.front()->name()); | |
675 EXPECT_EQ(dns_protocol::kTypePTR, records_from_cache.front()->type()); | |
676 EXPECT_EQ(dns_protocol::kClassIN, records_from_cache.front()->klass()); | |
677 | |
678 const PtrRecordRdata* ptr_rdata = | |
679 records_from_cache.front()->rdata<PtrRecordRdata>(); | |
680 | |
681 EXPECT_TRUE(ptr_rdata != NULL); | |
682 | |
683 EXPECT_EQ("hello._privet._tcp.local", | |
684 ptr_rdata->ptrdomain()); | |
685 } | |
686 | |
687 TEST_F(MDnsTest, Query) { | |
688 StrictMock<MockListenerDelegate> delegate_privet; | |
689 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
690 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
691 &delegate_privet); | |
692 | |
693 ASSERT_TRUE(listener_privet->SendQuery(false)); | |
694 | |
695 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
696 | |
697 // Active listeners should send queries when created. | |
698 | |
699 scoped_ptr<MDnsListener> listener_privet2 = test_factory_->CreateListener( | |
700 dns_protocol::kTypePTR, "_privet._tcp.local", true /*active*/, | |
701 false /*existing*/, &delegate_privet); | |
702 | |
703 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
704 } | |
705 | |
706 TEST_F(MDnsTest, TransactionNoCache) { | |
707 scoped_ptr<MDnsTransaction> transaction_privet = | |
708 test_factory_->CreateTransaction( | |
709 dns_protocol::kTypePTR, "_privet._tcp.local", | |
710 base::Bind(&MDnsTest::MockableRecordCallback, | |
711 base::Unretained(this))); | |
712 | |
713 EXPECT_TRUE(test_factory_->IsListeningForTests()); | |
714 | |
715 RecordParsedCopyContainer record_privet; | |
716 | |
717 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
718 | |
719 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionSuccess, _)) | |
720 .Times(Exactly(1)) | |
721 .WillOnce(Invoke(&record_privet, | |
722 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
723 | |
724 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
725 | |
726 time_system_->RunPendingTasks(); | |
727 | |
728 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
729 record_privet); | |
730 | |
731 EXPECT_FALSE(test_factory_->IsListeningForTests()); | |
732 } | |
733 | |
734 TEST_F(MDnsTest, TransactionWithCache) { | |
735 // Listener to force the factory to listen | |
736 StrictMock<MockListenerDelegate> delegate_irrelevant; | |
737 scoped_ptr<MDnsListener> listener_irrelevant = test_factory_->CreateListener( | |
738 dns_protocol::kTypeA, "codereview.chromium.local", false, false, | |
739 &delegate_irrelevant); | |
740 | |
741 EXPECT_TRUE(test_factory_->IsListeningForTests()); | |
742 | |
743 SendPacket(kSamplePacket1, sizeof(kSamplePacket1)); | |
744 | |
745 time_system_->RunPendingTasks(); | |
746 | |
747 RecordParsedCopyContainer record_privet; | |
748 | |
749 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionSuccess, _)) | |
750 .WillOnce(Invoke(&record_privet, | |
751 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
752 | |
753 scoped_ptr<MDnsTransaction> transaction_privet = | |
754 test_factory_->CreateTransaction( | |
755 dns_protocol::kTypePTR, "_privet._tcp.local", | |
756 base::Bind(&MDnsTest::MockableRecordCallback, | |
757 base::Unretained(this))); | |
758 | |
759 // "Expect no packet"? | |
760 | |
761 time_system_->RunPendingTasks(); | |
762 | |
763 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
764 record_privet); | |
765 } | |
766 | |
767 TEST_F(MDnsTest, AdditionalRecords) { | |
768 StrictMock<MockListenerDelegate> delegate_privet; | |
769 | |
770 RecordParsedCopyContainer record_privet; | |
771 | |
772 scoped_ptr<MDnsListener> listener_privet = test_factory_->CreateListener( | |
773 dns_protocol::kTypePTR, "_privet._tcp.local", false, false, | |
774 &delegate_privet); | |
775 | |
776 ASSERT_TRUE(test_factory_->IsListeningForTests()); | |
777 | |
778 // Send the same packet twice to ensure no records are double-counted. | |
779 | |
780 SendPacket(kSamplePacketAdditionalOnly, sizeof(kSamplePacket1)); | |
781 | |
782 EXPECT_CALL(delegate_privet, OnRecordUpdate(kMDnsRecordAdded, _)) | |
783 .Times(Exactly(1)) | |
784 .WillOnce(Invoke( | |
785 &record_privet, | |
786 &RecordParsedCopyContainer::SaveWithDummyArg)); | |
787 | |
788 time_system_->RunPendingTasks(); | |
789 | |
790 ExpectPtrRecord("_privet._tcp.local", "hello._privet._tcp.local", | |
791 record_privet); | |
792 } | |
793 | |
794 TEST_F(MDnsTest, TransactionTimeout) { | |
795 scoped_ptr<MDnsTransaction> transaction_privet = | |
796 test_factory_->CreateTransaction( | |
797 dns_protocol::kTypePTR, "_privet._tcp.local", | |
798 base::Bind(&MDnsTest::MockableRecordCallback, | |
799 base::Unretained(this))); | |
800 | |
801 EXPECT_TRUE(test_factory_->IsListeningForTests()); | |
802 | |
803 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
804 | |
805 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionTimeout, NULL)) | |
806 .Times(Exactly(1)); | |
807 | |
808 time_system_->SetNow(time_system_->Now() + base::TimeDelta::FromMinutes(5)); | |
809 | |
810 time_system_->RunPendingTasks(); | |
811 | |
812 EXPECT_FALSE(test_factory_->IsListeningForTests()); | |
813 } | |
814 | |
815 TEST_F(MDnsTest, TransactionReentrantDelete) { | |
816 transaction_ = test_factory_->CreateTransaction( | |
817 dns_protocol::kTypePTR, "_privet._tcp.local", | |
818 base::Bind(&MDnsTest::MockableRecordCallback, | |
819 base::Unretained(this))); | |
820 | |
821 EXPECT_TRUE(test_factory_->IsListeningForTests()); | |
822 | |
823 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); | |
824 | |
825 EXPECT_CALL(*this, MockableRecordCallback(kMDnsTransactionTimeout, NULL)) | |
826 .Times(Exactly(1)) | |
827 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction)); | |
828 | |
829 time_system_->SetNow(time_system_->Now() + base::TimeDelta::FromMinutes(5)); | |
830 | |
831 time_system_->RunPendingTasks(); | |
832 | |
833 EXPECT_EQ(NULL, transaction_.get()); | |
834 | |
835 EXPECT_FALSE(test_factory_->IsListeningForTests()); | |
836 } | |
837 | |
838 } // namespace | |
839 | |
840 } // namespace net | |
OLD | NEW |