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

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(OnServiceUpdated, void(ServiceWatcher::UpdateType,
256 const std::string&));
257 };
258
259 class ServiceDiscoveryTest : public ::testing::Test {
260 public:
261 ServiceDiscoveryTest()
262 : socket_factory_(new MockDatagramSocketFactory),
263 mdns_client_(
264 scoped_ptr<net::MDnsConnection::SocketFactory>(
265 socket_factory_)) {
266 net::MDnsClient::SetInstance(&mdns_client_);
267 }
268
269 virtual ~ServiceDiscoveryTest() {
270 net::MDnsClient::SetInstance(NULL);
271 }
272
273 protected:
274 void RunFor(base::TimeDelta time_period) {
275 base::CancelableCallback<void()> callback(base::Bind(
276 &ServiceDiscoveryTest::Stop, base::Unretained(this)));
277 base::MessageLoop::current()->PostDelayedTask(
278 FROM_HERE, callback.callback(), time_period);
279
280 base::MessageLoop::current()->Run();
281 callback.Cancel();
282 }
283
284 void Stop() {
285 base::MessageLoop::current()->Quit();
286 }
287
288 MockDatagramSocketFactory* socket_factory_;
289 net::MDnsClientImpl mdns_client_;
290 ServiceDiscoveryClientImpl service_discovery_client_;
291 base::MessageLoop loop_;
292 };
293
294 TEST_F(ServiceDiscoveryTest, AddRemoveService) {
295 scoped_ptr<ServiceWatcher> watcher;
296 StrictMock<MockServiceWatcherDelegate> delegate;
297
298 watcher = service_discovery_client_.CreateServiceWatcher(
299 "_privet._tcp.local", &delegate);
300
301 watcher->Start();
302
303 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
304 "hello._privet._tcp.local"))
305 .Times(Exactly(1));
306
307 socket_factory_->SimulateReceive(
308 kSamplePacketPTR, sizeof(kSamplePacketPTR));
309
310 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_REMOVED,
311 "hello._privet._tcp.local"))
312 .Times(Exactly(1));
313
314 RunFor(base::TimeDelta::FromSeconds(2));
315 };
316
317 TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
318 scoped_ptr<ServiceWatcher> watcher;
319 StrictMock<MockServiceWatcherDelegate> delegate;
320
321 watcher = service_discovery_client_.CreateServiceWatcher(
322 "_privet._tcp.local", &delegate);
323
324 watcher->Start();
325
326 EXPECT_CALL(*socket_factory_, OnSendTo(_))
327 .Times(2);
328
329 watcher->DiscoverNewServices(false);
330 };
331
332 TEST_F(ServiceDiscoveryTest, GetAvailableServices) {
333 NiceMock<MockServiceWatcherDelegate> delegate;
334
335 std::vector<std::string> data_expected;
336 std::vector<std::string> data;
337
338 data_expected.push_back("hello._privet._tcp.local");
339
340 scoped_ptr<ServiceWatcher> watcher =
341 service_discovery_client_.CreateServiceWatcher(
342 "_privet._tcp.local", &delegate);
343
344 watcher->Start();
345
346 socket_factory_->SimulateReceive(
347 kSamplePacketPTR, sizeof(kSamplePacketPTR));
348
349 watcher->GetAvailableServices(&data);
350
351 EXPECT_EQ(data, data_expected);
352 };
353
354
355 TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
356 NiceMock<MockServiceWatcherDelegate> delegate_irrelevant;
357 scoped_ptr<ServiceWatcher> watcher_irrelevant =
358 service_discovery_client_.CreateServiceWatcher(
359 "_privet._tcp.local", &delegate_irrelevant);
360
361 watcher_irrelevant->Start();
362
363 socket_factory_->SimulateReceive(
364 kSamplePacketPTR, sizeof(kSamplePacketPTR));
365
366 StrictMock<MockServiceWatcherDelegate> delegate;
367 scoped_ptr<ServiceWatcher> watcher =
368 service_discovery_client_.CreateServiceWatcher(
369 "_privet._tcp.local", &delegate);
370
371 watcher->Start();
372
373 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
374 "hello._privet._tcp.local"))
375 .Times(Exactly(1));
376
377 watcher->ReadCachedServices();
378 };
379
380 TEST_F(ServiceDiscoveryTest, OnServiceChanged) {
381 StrictMock<MockServiceWatcherDelegate> delegate;
382 scoped_ptr<ServiceWatcher> watcher =
383 service_discovery_client_.CreateServiceWatcher(
384 "_privet._tcp.local", &delegate);
385
386 watcher->Start();
387
388 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
389 "hello._privet._tcp.local"))
390 .Times(Exactly(1));
391
392 socket_factory_->SimulateReceive(
393 kSamplePacketPTR, sizeof(kSamplePacketPTR));
394
395 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_CHANGED,
396 "hello._privet._tcp.local"))
397 .Times(Exactly(2));
398
399 socket_factory_->SimulateReceive(
400 kSamplePacketSRV, sizeof(kSamplePacketSRV));
401
402 socket_factory_->SimulateReceive(
403 kSamplePacketTXT, sizeof(kSamplePacketTXT));
404
405 watcher->ReadCachedServices();
406 };
407
408
409 class ServiceResolverTest : public ServiceDiscoveryTest {
410 public:
411 ServiceResolverTest() {
412 metadata_expected_.push_back("hello");
413 address_expected_ = net::HostPortPair("myhello.local", 8888);
414 ip_address_expected_.push_back(1);
415 ip_address_expected_.push_back(2);
416 ip_address_expected_.push_back(3);
417 ip_address_expected_.push_back(4);
418 }
419
420 ~ServiceResolverTest() {
421 }
422
423 void SetUp() {
424 resolver_ = service_discovery_client_.CreateServiceResolver(
425 "hello._privet._tcp.local",
426 base::Bind(&ServiceResolverTest::OnFinishedResolving,
427 base::Unretained(this)));
428 }
429
430 void OnFinishedResolving(ServiceResolver::RequestStatus request_status,
431 const ServiceDescription& service_description) {
432 OnFinishedResolvingInternal(request_status);
433 }
434
435 MOCK_METHOD1(OnFinishedResolvingInternal, void(
436 ServiceResolver::RequestStatus));
437
438 protected:
439 scoped_ptr<ServiceResolver> resolver_;
440 net::IPAddressNumber ip_address_;
441 net::HostPortPair address_expected_;
442 std::vector<std::string> metadata_expected_;
443 net::IPAddressNumber ip_address_expected_;
444 };
445
446 TEST_F(ServiceResolverTest, TxtAndSrvButNoA) {
447 EXPECT_CALL(*socket_factory_, OnSendTo(_))
448 .Times(4);
449
450 EXPECT_FALSE(resolver_->IsResolving());
451 EXPECT_FALSE(resolver_->HasResolved());
452 EXPECT_TRUE(resolver_->StartResolving());
453 EXPECT_TRUE(resolver_->IsResolving());
454 EXPECT_FALSE(resolver_->HasResolved());
455
456 socket_factory_->SimulateReceive(
457 kSamplePacketSRV, sizeof(kSamplePacketSRV));
458
459 base::MessageLoop::current()->RunUntilIdle();
460
461 EXPECT_CALL(*this, OnFinishedResolvingInternal(
462 ServiceResolver::STATUS_SUCCESS));
463
464 socket_factory_->SimulateReceive(
465 kSamplePacketTXT, sizeof(kSamplePacketTXT));
466
467 EXPECT_EQ(address_expected_.ToString(),
468 resolver_->GetServiceDescription().address.ToString());
469 EXPECT_EQ(metadata_expected_, resolver_->GetServiceDescription().metadata);
470 EXPECT_EQ(net::IPAddressNumber(),
471 resolver_->GetServiceDescription().ip_address);
472 };
473
474 TEST_F(ServiceResolverTest, TxtSrvAndA) {
475 EXPECT_CALL(*socket_factory_, OnSendTo(_))
476 .Times(4);
477
478 EXPECT_FALSE(resolver_->IsResolving());
479 EXPECT_FALSE(resolver_->HasResolved());
480 EXPECT_TRUE(resolver_->StartResolving());
481 EXPECT_TRUE(resolver_->IsResolving());
482 EXPECT_FALSE(resolver_->HasResolved());
483
484 EXPECT_CALL(*this, OnFinishedResolvingInternal(
485 ServiceResolver::STATUS_SUCCESS));
486
487 socket_factory_->SimulateReceive(
488 kSamplePacketTXT, sizeof(kSamplePacketTXT));
489
490 socket_factory_->SimulateReceive(
491 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
492
493 EXPECT_EQ(address_expected_.ToString(),
494 resolver_->GetServiceDescription().address.ToString());
495 EXPECT_EQ(metadata_expected_, resolver_->GetServiceDescription().metadata);
496 EXPECT_EQ(ip_address_expected_,
497 resolver_->GetServiceDescription().ip_address);
498 };
499
500 TEST_F(ServiceResolverTest, JustSrv) {
501 EXPECT_CALL(*socket_factory_, OnSendTo(_))
502 .Times(4);
503
504 EXPECT_FALSE(resolver_->IsResolving());
505 EXPECT_FALSE(resolver_->HasResolved());
506 EXPECT_TRUE(resolver_->StartResolving());
507 EXPECT_TRUE(resolver_->IsResolving());
508 EXPECT_FALSE(resolver_->HasResolved());
509
510 EXPECT_CALL(*this, OnFinishedResolvingInternal(
511 ServiceResolver::STATUS_SUCCESS));
512
513 socket_factory_->SimulateReceive(
514 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
515
516 // TODO(noamsml): When NSEC record support is added, change this to use an
517 // NSEC record.
518 RunFor(base::TimeDelta::FromSeconds(4));
519
520 EXPECT_EQ(address_expected_.ToString(),
521 resolver_->GetServiceDescription().address.ToString());
522 EXPECT_EQ(std::vector<std::string>() ,
523 resolver_->GetServiceDescription().metadata);
524 EXPECT_EQ(ip_address_expected_,
525 resolver_->GetServiceDescription().ip_address);
526 };
527
528 TEST_F(ServiceResolverTest, WithNothing) {
529 EXPECT_CALL(*socket_factory_, OnSendTo(_))
530 .Times(4);
531
532 EXPECT_FALSE(resolver_->IsResolving());
533 EXPECT_FALSE(resolver_->HasResolved());
534 EXPECT_TRUE(resolver_->StartResolving());
535 EXPECT_TRUE(resolver_->IsResolving());
536 EXPECT_FALSE(resolver_->HasResolved());
537
538 EXPECT_CALL(*this, OnFinishedResolvingInternal(
539 ServiceResolver::STATUS_REQUEST_TIMEOUT));
540
541 // TODO(noamsml): When NSEC record support is added, change this to use an
542 // NSEC record.
543 RunFor(base::TimeDelta::FromSeconds(4));
544 };
545
546 } // namespace
547
548 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698