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