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