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

Side by Side Diff: chrome/browser/local_discovery/service_discovery_client_unittest.cc

Issue 16272006: In-browser DNS-based service discovery system (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mdns_implementation
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/weak_ptr.h"
6 #include "chrome/browser/local_discovery/service_discovery_client_impl.h"
7 #include "net/base/net_errors.h"
8 #include "net/dns/dns_protocol.h"
9 #include "net/dns/mdns_client_impl.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 using ::testing::_;
14 using ::testing::Invoke;
15 using ::testing::StrictMock;
16 using ::testing::NiceMock;
17 using ::testing::Mock;
18 using ::testing::SaveArg;
19 using ::testing::SetArgPointee;
20 using ::testing::Return;
21 using ::testing::Exactly;
22
23 namespace local_discovery {
24
25 namespace {
26
27 const char kSamplePacketPTR[] = {
28 // Header
29 0x00, 0x00, // ID is zeroed out
30 0x81, 0x80, // Standard query response, RA, no error
31 0x00, 0x00, // No questions (for simplicity)
32 0x00, 0x01, // 1 RR (answers)
33 0x00, 0x00, // 0 authority RRs
34 0x00, 0x00, // 0 additional RRs
35
36 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
37 0x04, '_', 't', 'c', 'p',
38 0x05, 'l', 'o', 'c', 'a', 'l',
39 0x00,
40 0x00, 0x0c, // TYPE is PTR.
41 0x00, 0x01, // CLASS is IN.
42 0x00, 0x00, // TTL (4 bytes) is 1 second.
43 0x00, 0x01,
44 0x00, 0x08, // RDLENGTH is 8 bytes.
45 0x05, 'h', 'e', 'l', 'l', 'o',
46 0xc0, 0x0c
47 };
48
49 const char kSamplePacketSRV[] = {
50 // Header
51 0x00, 0x00, // ID is zeroed out
52 0x81, 0x80, // Standard query response, RA, no error
53 0x00, 0x00, // No questions (for simplicity)
54 0x00, 0x01, // 1 RR (answers)
55 0x00, 0x00, // 0 authority RRs
56 0x00, 0x00, // 0 additional RRs
57
58 0x05, 'h', 'e', 'l', 'l', 'o',
59 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
60 0x04, '_', 't', 'c', 'p',
61 0x05, 'l', 'o', 'c', 'a', 'l',
62 0x00,
63 0x00, 0x21, // TYPE is SRV.
64 0x00, 0x01, // CLASS is IN.
65 0x00, 0x00, // TTL (4 bytes) is 1 second.
66 0x00, 0x01,
67 0x00, 0x15, // RDLENGTH is 21 bytes.
68 0x00, 0x00,
69 0x00, 0x00,
70 0x22, 0xb8, // port 8888
71 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
72 0x05, 'l', 'o', 'c', 'a', 'l',
73 0x00,
74 };
75
76 const char kSamplePacketTXT[] = {
77 // Header
78 0x00, 0x00, // ID is zeroed out
79 0x81, 0x80, // Standard query response, RA, no error
80 0x00, 0x00, // No questions (for simplicity)
81 0x00, 0x01, // 1 RR (answers)
82 0x00, 0x00, // 0 authority RRs
83 0x00, 0x00, // 0 additional RRs
84
85 0x05, 'h', 'e', 'l', 'l', 'o',
86 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
87 0x04, '_', 't', 'c', 'p',
88 0x05, 'l', 'o', 'c', 'a', 'l',
89 0x00,
90 0x00, 0x10, // TYPE is PTR.
91 0x00, 0x01, // CLASS is IN.
92 0x00, 0x00, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
93 0x00, 0x01,
94 0x00, 0x06, // RDLENGTH is 21 bytes.
95 0x05, 'h', 'e', 'l', 'l', 'o'
96 };
97
98 const char kSamplePacketSRVA[] = {
99 // Header
100 0x00, 0x00, // ID is zeroed out
101 0x81, 0x80, // Standard query response, RA, no error
102 0x00, 0x00, // No questions (for simplicity)
103 0x00, 0x02, // 2 RR (answers)
104 0x00, 0x00, // 0 authority RRs
105 0x00, 0x00, // 0 additional RRs
106
107 0x05, 'h', 'e', 'l', 'l', 'o',
108 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
109 0x04, '_', 't', 'c', 'p',
110 0x05, 'l', 'o', 'c', 'a', 'l',
111 0x00,
112 0x00, 0x21, // TYPE is SRV.
113 0x00, 0x01, // CLASS is IN.
114 0x00, 0x00, // TTL (4 bytes) is 16 seconds.
115 0x00, 0x10,
116 0x00, 0x15, // RDLENGTH is 21 bytes.
117 0x00, 0x00,
118 0x00, 0x00,
119 0x22, 0xb8, // port 8888
120 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
121 0x05, 'l', 'o', 'c', 'a', 'l',
122 0x00,
123
124 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
125 0x05, 'l', 'o', 'c', 'a', 'l',
126 0x00,
127 0x00, 0x01, // TYPE is A.
128 0x00, 0x01, // CLASS is IN.
129 0x00, 0x00, // TTL (4 bytes) is 16 seconds.
130 0x00, 0x10,
131 0x00, 0x04, // RDLENGTH is 4 bytes.
132 0x01, 0x02,
133 0x03, 0x04,
134 };
135
136
137 class MockDatagramSocket : public net::DatagramServerSocket {
138 public:
139 int Listen(const net::IPEndPoint& address) {
140 return ListenInternal(address.ToString());
141 }
142
143 MOCK_METHOD1(ListenInternal, int(const std::string& address));
144
145 MOCK_METHOD4(RecvFrom, int(net::IOBuffer* buffer, int size,
146 net::IPEndPoint* address,
147 const net::CompletionCallback& callback));
148
149 int SendTo(net::IOBuffer* buf, int buf_len, const net::IPEndPoint& address,
150 const net::CompletionCallback& callback) {
151 return SendToInternal(std::string(buf->data(), buf_len), address.ToString(),
152 callback);
153 }
154
155 MOCK_METHOD3(SendToInternal, int(const std::string& packet,
156 const std::string address,
157 const net::CompletionCallback& callback));
158
159 MOCK_METHOD1(SetReceiveBufferSize, bool(int32 size));
160 MOCK_METHOD1(SetSendBufferSize, bool(int32 size));
161
162 MOCK_METHOD0(Close, void());
163
164 MOCK_CONST_METHOD1(GetPeerAddress, int(net::IPEndPoint* address));
165 MOCK_CONST_METHOD1(GetLocalAddress, int(net::IPEndPoint* address));
166 MOCK_CONST_METHOD0(NetLog, const net::BoundNetLog&());
167
168 MOCK_METHOD0(AllowAddressReuse, void());
169 MOCK_METHOD0(AllowBroadcast, void());
170
171 int JoinGroup(const net::IPAddressNumber& group_address) const {
172 return JoinGroupInternal(net::IPAddressToString(group_address));
173 }
174
175 MOCK_CONST_METHOD1(JoinGroupInternal, int(const std::string& group));
176
177 int LeaveGroup(const net::IPAddressNumber& group_address) const {
178 return LeaveGroupInternal(net::IPAddressToString(group_address));
179 }
180
181 MOCK_CONST_METHOD1(LeaveGroupInternal, int(const std::string& group));
182
183 MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
184
185 MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
186 };
187
188 class MockDatagramSocketFactory
189 : public net::MDnsConnection::SocketFactory {
190 public:
191 MockDatagramSocketFactory() {
192 }
193
194 virtual ~MockDatagramSocketFactory() {
195 }
196
197 virtual scoped_ptr<net::DatagramServerSocket> CreateSocket() OVERRIDE {
198 scoped_ptr<MockDatagramSocket> new_socket(
199 new NiceMock<MockDatagramSocket>);
200
201 ON_CALL(*new_socket, SendToInternal(_, _, _))
202 .WillByDefault(Invoke(
203 this,
204 &MockDatagramSocketFactory::SendToInternal));
205
206 ON_CALL(*new_socket, RecvFrom(_, _, _, _))
207 .WillByDefault(Invoke(
208 this,
209 &MockDatagramSocketFactory::RecvFromInternal));
210
211 return new_socket.PassAs<net::DatagramServerSocket>();
212 }
213
214 int SendToInternal(const std::string& packet, const std::string& address,
215 const net::CompletionCallback& callback) {
216 OnSendTo(packet);
217 return packet.size();
218 }
219
220 // The latest recieve callback is always saved, since the net::MDnsConnection
221 // does not care which socket a packet is received on.
222 int RecvFromInternal(net::IOBuffer* buffer, int size,
223 net::IPEndPoint* address,
224 const net::CompletionCallback& callback) {
225 recv_buffer_ = buffer;
226 recv_buffer_size_ = size;
227 recv_callback_ = callback;
228 return net::ERR_IO_PENDING;
229 }
230
231 void SimulateReceive(const char* packet, int size) {
232 DCHECK(recv_buffer_size_ >= size);
233 DCHECK(recv_buffer_.get());
234 DCHECK(!recv_callback_.is_null());
235
236 memcpy(recv_buffer_->data(), packet, size);
237 net::CompletionCallback recv_callback = recv_callback_;
238 recv_callback_.Reset();
239 recv_callback.Run(size);
240 }
241
242 MOCK_METHOD1(OnSendTo, void(const std::string&));
243
244 private:
245 scoped_refptr<net::IOBuffer> recv_buffer_;
246 int recv_buffer_size_;
247 net::CompletionCallback recv_callback_;
248 };
249
250 class MockServiceWatcherDelegate : public ServiceWatcher::Delegate {
251 public:
252 MockServiceWatcherDelegate() {}
253 virtual ~MockServiceWatcherDelegate() {}
254
255 MOCK_METHOD2(OnServiceStatusChanged, void(bool, const std::string&));
256 MOCK_METHOD1(OnServiceChanged, void(const std::string&));
257 };
258
259 class ServiceDiscoveryTest : public ::testing::Test {
260 public:
261 ServiceDiscoveryTest() : socket_factory_(new MockDatagramSocketFactory),
Vitaly Buka (NO REVIEWS) 2013/06/18 23:01:46 maybe break before :
Noam Samuel 2013/06/19 18:46:22 Done.
262 mdns_client_(
263 scoped_ptr<net::MDnsConnection::SocketFactory>(
264 socket_factory_)) {
265 net::MDnsClient::SetInstance(&mdns_client_);
266 }
267
268 virtual ~ServiceDiscoveryTest() {
269 net::MDnsClient::SetInstance(NULL);
270 }
271
272 protected:
273 void RunFor(base::TimeDelta time_period) {
274 base::CancelableCallback<void()> callback(base::Bind(
275 &ServiceDiscoveryTest::Stop, base::Unretained(this)));
276 base::MessageLoop::current()->PostDelayedTask(
277 FROM_HERE, callback.callback(), time_period);
278
279 base::MessageLoop::current()->Run();
280 callback.Cancel();
281 }
282
283 void Stop() {
284 base::MessageLoop::current()->Quit();
285 }
286
287 MockDatagramSocketFactory* socket_factory_;
288 net::MDnsClientImpl mdns_client_;
289 ServiceDiscoveryClientImpl service_discovery_client_;
290 base::MessageLoop loop_;
291 };
292
293 TEST_F(ServiceDiscoveryTest, AddRemoveService) {
294 scoped_ptr<ServiceWatcher> watcher;
295 StrictMock<MockServiceWatcherDelegate> delegate;
296
297 watcher = service_discovery_client_.CreateServiceWatcher(
298 "_privet._tcp.local", &delegate);
299
300 watcher->Start();
301
302 EXPECT_CALL(delegate,
303 OnServiceStatusChanged(true, "hello._privet._tcp.local"))
304 .Times(Exactly(1));
305
306 socket_factory_->SimulateReceive(
307 kSamplePacketPTR, sizeof(kSamplePacketPTR));
308
309 EXPECT_CALL(delegate,
310 OnServiceStatusChanged(false, "hello._privet._tcp.local"))
311 .Times(Exactly(1));
312
313 RunFor(base::TimeDelta::FromSeconds(2));
314 };
315
316 TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
317 scoped_ptr<ServiceWatcher> watcher;
318 StrictMock<MockServiceWatcherDelegate> delegate;
319
320 watcher = service_discovery_client_.CreateServiceWatcher(
321 "_privet._tcp.local", &delegate);
322
323 watcher->Start();
324
325 EXPECT_CALL(*socket_factory_, OnSendTo(_))
326 .Times(2);
327
328 watcher->DiscoverNewServices(false);
329 };
330
331 TEST_F(ServiceDiscoveryTest, GetAvailableServices) {
332 NiceMock<MockServiceWatcherDelegate> delegate;
333
334 std::vector<std::string> data_expected;
335 std::vector<std::string> data;
336
337 data_expected.push_back("hello._privet._tcp.local");
338
339 scoped_ptr<ServiceWatcher> watcher =
340 service_discovery_client_.CreateServiceWatcher(
341 "_privet._tcp.local", &delegate);
342
343 watcher->Start();
344
345 socket_factory_->SimulateReceive(
346 kSamplePacketPTR, sizeof(kSamplePacketPTR));
347
348 watcher->GetAvailableServices(&data);
349
350 EXPECT_EQ(data, data_expected);
351 };
352
353
354 TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
355 NiceMock<MockServiceWatcherDelegate> delegate_irrelevant;
356 scoped_ptr<ServiceWatcher> watcher_irrelevant =
357 service_discovery_client_.CreateServiceWatcher(
358 "_privet._tcp.local", &delegate_irrelevant);
359
360 watcher_irrelevant->Start();
361
362 socket_factory_->SimulateReceive(
363 kSamplePacketPTR, sizeof(kSamplePacketPTR));
364
365 StrictMock<MockServiceWatcherDelegate> delegate;
366 scoped_ptr<ServiceWatcher> watcher =
367 service_discovery_client_.CreateServiceWatcher(
368 "_privet._tcp.local", &delegate);
369
370 watcher->Start();
371
372 EXPECT_CALL(delegate,
373 OnServiceStatusChanged(true, "hello._privet._tcp.local"))
374 .Times(Exactly(1));
375
376 watcher->ReadCachedServices();
377 };
378
379 TEST_F(ServiceDiscoveryTest, OnServiceChanged) {
380 StrictMock<MockServiceWatcherDelegate> delegate;
381 scoped_ptr<ServiceWatcher> watcher =
382 service_discovery_client_.CreateServiceWatcher(
383 "_privet._tcp.local", &delegate);
384
385 watcher->Start();
386
387 EXPECT_CALL(delegate,
388 OnServiceStatusChanged(true, "hello._privet._tcp.local"))
389 .Times(Exactly(1));
390
391 socket_factory_->SimulateReceive(
392 kSamplePacketPTR, sizeof(kSamplePacketPTR));
393
394 EXPECT_CALL(delegate,
395 OnServiceChanged("hello._privet._tcp.local"))
396 .Times(Exactly(2));
397
398 socket_factory_->SimulateReceive(
399 kSamplePacketSRV, sizeof(kSamplePacketSRV));
400
401 socket_factory_->SimulateReceive(
402 kSamplePacketTXT, sizeof(kSamplePacketTXT));
403
404 watcher->ReadCachedServices();
405 };
406
407
408 class ServiceResolverTest : public ServiceDiscoveryTest {
409 public:
410 ServiceResolverTest() {
411 metadata_expected_.push_back("hello");
412 address_expected_ = net::HostPortPair("myhello.local", 8888);
413 ip_address_expected_.push_back(1);
414 ip_address_expected_.push_back(2);
415 ip_address_expected_.push_back(3);
416 ip_address_expected_.push_back(4);
417 }
418
419 ~ServiceResolverTest() {
420 }
421
422 void SetUp() {
423 resolver_ = service_discovery_client_.CreateServiceResolver(
424 "hello._privet._tcp.local",
425 base::Bind(&ServiceResolverTest::OnFinishedResolving,
426 base::Unretained(this)));
427 }
428
429 MOCK_METHOD1(OnFinishedResolving, void(ServiceResolver::RequestStatus));
430
431 protected:
432 scoped_ptr<ServiceResolver> resolver_;
433 net::IPAddressNumber ip_address_;
434 net::HostPortPair address_expected_;
435 std::vector<std::string> metadata_expected_;
436 net::IPAddressNumber ip_address_expected_;
437 };
438
439 TEST_F(ServiceResolverTest, TxtAndSrvButNoA) {
440 EXPECT_CALL(*socket_factory_, OnSendTo(_))
441 .Times(4);
442
443 EXPECT_FALSE(resolver_->IsResolving());
444 EXPECT_FALSE(resolver_->HasResolved());
445 EXPECT_TRUE(resolver_->StartResolving());
446 EXPECT_TRUE(resolver_->IsResolving());
447 EXPECT_FALSE(resolver_->HasResolved());
448
449 socket_factory_->SimulateReceive(
450 kSamplePacketSRV, sizeof(kSamplePacketSRV));
451
452 base::MessageLoop::current()->RunUntilIdle();
453
454 EXPECT_CALL(*this, OnFinishedResolving(ServiceResolver::STATUS_SUCCESS));
455
456 socket_factory_->SimulateReceive(
457 kSamplePacketTXT, sizeof(kSamplePacketTXT));
458
459 EXPECT_EQ(address_expected_.ToString(),
460 resolver_->GetService().address.ToString());
461 EXPECT_EQ(metadata_expected_, resolver_->GetService().metadata);
462 EXPECT_EQ(net::IPAddressNumber(), resolver_->GetService().ip_address);
463 };
464
465 TEST_F(ServiceResolverTest, TxtSrvAndA) {
466 EXPECT_CALL(*socket_factory_, OnSendTo(_))
467 .Times(4);
468
469 EXPECT_FALSE(resolver_->IsResolving());
470 EXPECT_FALSE(resolver_->HasResolved());
471 EXPECT_TRUE(resolver_->StartResolving());
472 EXPECT_TRUE(resolver_->IsResolving());
473 EXPECT_FALSE(resolver_->HasResolved());
474
475 EXPECT_CALL(*this, OnFinishedResolving(ServiceResolver::STATUS_SUCCESS));
476
477 socket_factory_->SimulateReceive(
478 kSamplePacketTXT, sizeof(kSamplePacketTXT));
479
480 socket_factory_->SimulateReceive(
481 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
482
483 EXPECT_EQ(address_expected_.ToString(),
484 resolver_->GetService().address.ToString());
485 EXPECT_EQ(metadata_expected_, resolver_->GetService().metadata);
486 EXPECT_EQ(ip_address_expected_, resolver_->GetService().ip_address);
487 };
488
489 TEST_F(ServiceResolverTest, JustSrv) {
490 EXPECT_CALL(*socket_factory_, OnSendTo(_))
491 .Times(4);
492
493 EXPECT_FALSE(resolver_->IsResolving());
494 EXPECT_FALSE(resolver_->HasResolved());
495 EXPECT_TRUE(resolver_->StartResolving());
496 EXPECT_TRUE(resolver_->IsResolving());
497 EXPECT_FALSE(resolver_->HasResolved());
498
499 EXPECT_CALL(*this, OnFinishedResolving(ServiceResolver::STATUS_SUCCESS));
500
501 socket_factory_->SimulateReceive(
502 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
503
504 // TODO(noamsml): When NSEC record support is added, change this to use an
505 // NSEC record.
506 RunFor(base::TimeDelta::FromSeconds(4));
507
508 EXPECT_EQ(address_expected_.ToString(),
509 resolver_->GetService().address.ToString());
510 EXPECT_EQ(std::vector<std::string>() , resolver_->GetService().metadata);
511 EXPECT_EQ(ip_address_expected_, resolver_->GetService().ip_address);
512 };
513
514 TEST_F(ServiceResolverTest, WithNothing) {
515 EXPECT_CALL(*socket_factory_, OnSendTo(_))
516 .Times(4);
517
518 EXPECT_FALSE(resolver_->IsResolving());
519 EXPECT_FALSE(resolver_->HasResolved());
520 EXPECT_TRUE(resolver_->StartResolving());
521 EXPECT_TRUE(resolver_->IsResolving());
522 EXPECT_FALSE(resolver_->HasResolved());
523
524 EXPECT_CALL(*this, OnFinishedResolving(ServiceResolver::STATUS_TIMEOUT));
525
526 // TODO(noamsml): When NSEC record support is added, change this to use an
527 // NSEC record.
528 RunFor(base::TimeDelta::FromSeconds(4));
529 };
530
531 } // namespace
532
533 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698